Data Cleaning
- Incident Datasets
#Incident Basketball Data
#BASKETBALL Incident dataset
Incident_B <- Incident_B %>% #189 -> 128 obs.
filter(Incident.Type=="Injury") %>%
filter(Status %in% c("Out", "As Tolerated")) %>%
filter(Result.of.Sport.Participation=="Yes") %>%
select(-Result.of.Sport.Participation)
incident_B <- subset(Incident_B,select=c("anon_id","Date","Sport", "Position", "Date.of.Injury...Onset.of.symptoms", "Side", "Body.Part.","Total.Time.Injured", "Tissue.Type","OSICS14.Code","OSICS10.Diagnosis","Final.Diagnosis", "Recurrence.of.Injury", "Injury.Prognosis", "General.mechanism","Specific.Mechanism","Injured.Position", "Month", "Year","Status","Season.","Start.of.Status", "End.Date", "Total.Time.Injured")) #add,"Injured.Position",
#53 obs. + 27 vars.
#Lower body injuries
lower_body <- c("Thigh","Ankle","Lower leg","Knee","Foot","Groin/hip")
incident_B$LB.Injury <- ifelse(incident_B$Body.Part. %in% c("Thigh", "Ankle", "Lower leg", "Knee", "Foot", "Groin/hip"),1,0) #lower body Injury Binary
sum(incident_B$LB.Injury)
[1] 42
#ACL injury (most intense LB injury)
incident_B$ACL <- ifelse(incident_B$OSICS14.Code %in% c("KL1","KLA"),1,0)
sum(incident_B$ACL)
[1] 1
#HSI injury (overuse injury)
incident_B$HSI <- ifelse(incident_B$OSICS14.Code %in% c("TM1","TMB","TMS"),1,0)
sum(incident_B$HSI)
[1] 0
#12/5/23-1/2/25 DATE RANGE (2 years)
#converting all dates
incident_b <- incident_B %>%
mutate(Total.Time.Injured = sum(Total.Time.Injured, na.rm = TRUE),
Date = as.Date(Date, format = '%m/%d/%Y'),
Start.of.Status=as.Date(Start.of.Status,format='%m/%d/%Y'),
End.Date= as.Date(End.Date, format='%m/%d/%Y'),
Date.of.Injury...Onset.of.symptoms= as.Date(Date.of.Injury...Onset.of.symptoms, format='%m/%d/%Y'))
#create a length of status variable (Out, limited,as tolerated, full go)
incident_b$Length.of.Status <- difftime(incident_b$End.Date, incident_b$Start.of.Status,units=c("days"))
library(stringr)
#rename one datapoint from position
incident_b <- incident_b %>%
mutate(Position=case_when(
str_detect(Position, "Primary: Forward")~ "Forward",
str_detect(Position, "Forward")~ "Forward",
str_detect(Position, "Center")~ "Center",
str_detect(Position, "Guard")~ "Guard",
TRUE~Position
))
#rename sport column to better compare when joining datasets
incident_b <- incident_b %>%
mutate(Sport=case_when(
str_detect(Sport, "Primary: BASKETBALL")~ "Basketball",
str_detect(Sport, "BASKETBALL")~ "Basketball"
))
In womens basketball we have 42 total lower body injuries, 1 of those
injuries are ACL injuries, and none are HSI injuries.
#Incident Soccer Data
#SOCCER INCIDENT dataset
Incident_S <- Incident_S %>% #361 -> 288 obs.
filter(Incident.Type=="Injury") %>%
filter(Status %in% c("Out", "As Tolerated")) %>%
filter(Result.of.Sport.Participation=="Yes") %>%
select(-Result.of.Sport.Participation)
incident_S <- subset(Incident_S,select=c("anon_id","Date","Sport", "Position", "Date.of.Injury...Onset.of.symptoms", "Side", "Body.Part.", "Total.Time.Injured", "Tissue.Type","OSICS14.Code","OSICS10.Diagnosis", "Final.Diagnosis", "Recurrence.of.Injury", "Injury.Prognosis", "General.mechanism","Specific.Mechanism","Injured.While.", "Month", "Year","Incident.Type","Status", "Season.","Start.of.Status", "End.Date"))
#88 obs. + 27 vars.
#Lower body injuriy Binary
incident_S$LB.Injury <- ifelse(incident_S$Body.Part. %in% c("Thigh", "Ankle", "Lower leg", "Knee", "Foot", "Groin/hip"),1,0)
sum(incident_S$LB.Injury)
[1] 76
#ACL injury (most intense LB injury)
incident_S$ACL <- ifelse(incident_S$OSICS14.Code %in% c("KL1","KLA"),1,0)
sum(incident_S$ACL)
[1] 1
#HSI injury (overuse injury)
incident_S$HSI <- ifelse(incident_S$OSICS14.Code %in% c("TM1","TMB","TMS"),1,0)
sum(incident_S$HSI)
[1] 2
#5/8/23- 1/15/25 (year and a half ish)
#converting all dates
incident_s <- incident_S %>%
mutate(Total.Time.Injured = sum(Total.Time.Injured, na.rm = TRUE),
Date = as.Date(Date, format = '%m/%d/%Y'),
Start.of.Status=as.Date(Start.of.Status,format='%m/%d/%Y'),
End.Date= as.Date(End.Date, format='%m/%d/%Y'),
Date.of.Injury...Onset.of.symptoms= as.Date(Date.of.Injury...Onset.of.symptoms, format='%m/%d/%Y'),
Sport=case_when(
str_detect(Sport, "SOCCER")~ "Soccer" #rename sport column to better compare when joining datasets
))
#create a length of status variable (Out, limited,as tolerated, full go)
incident_s$Length.of.Status <- difftime(incident_s$End.Date, incident_s$Start.of.Status,units=c("days"))
In women’s soccer there is a total of 76 lower body injuries, with 1
of them being ACL injuries, and 2 being HSI injuries.
#Incident Lacrosse Data
#LACROSSE incident dataset
Incident_L <- Incident_L %>% #139 -> 86 obs.
filter(Incident.Type=="Injury") %>%
filter(Status %in% c("Out", "As Tolerated")) %>%
filter(Result.of.Sport.Participation=="Yes") %>%
select(-Result.of.Sport.Participation)
incident_L <- subset(Incident_L,select=c("anon_id","Date","Sport", "Position", "Date.of.Injury...Onset.of.symptoms", "Side", "Body.Part.", "Tissue.Type","OSICS14.Code","OSICS10.Diagnosis", "Final.Diagnosis", "Recurrence.of.Injury", "Injury.Prognosis", "General.mechanism","Specific.Mechanism", "Injured.While.", "Month", "Year","Incident.Type","Status", "Season.","Start.of.Status", "End.Date", "Total.Time.Injured")) #34obs
#Lower body injury binary
incident_L$LB.Injury <- ifelse(incident_L$Body.Part. %in% c("Thigh", "Ankle", "Lower leg", "Knee", "Foot", "Groin/hip"),1,0)
sum(incident_L$LB.Injury)
[1] 31
#ACL injury (most intense LB injury)
incident_L$ACL <- ifelse(incident_L$OSICS14.Code %in% c("KL1","KLA"),1,0)
sum(incident_L$ACL)
[1] 3
#HSI injury (overuse injury)
incident_L$HSI <- ifelse(incident_L$OSICS14.Code %in% c("TM1","TMB","TMS"),1,0)
sum(incident_L$HSI)
[1] 4
#4/12/23-4/18/25 (2 years)
#converting all dates
incident_l <- incident_L %>%
mutate(Total.Time.Injured = sum(Total.Time.Injured, na.rm = TRUE),
Date = as.Date(Date, format = '%m/%d/%Y'),
Start.of.Status=as.Date(Start.of.Status,format='%m/%d/%Y'),
End.Date= as.Date(End.Date, format='%m/%d/%Y'),
Date.of.Injury...Onset.of.symptoms= as.Date(Date.of.Injury...Onset.of.symptoms, format='%m/%d/%Y'),
Sport=case_when(
str_detect(Sport, "LACROSSE")~ "Lacrosse"
)
)
#create a length of status variable (Out, limited,as tolerated, full go)
incident_l$Length.of.Status <- difftime(incident_l$End.Date, incident_l$Start.of.Status,units=c("days"))
In womens lacrosse 31 lower body injuries occurred, 3 being ACL
related, 4 being HSI injury related.
#Incident Volleyball Data
#VOLLEYBALL incident dataset
Incident_V <- Incident_V %>% #220 -> 135 obs.
filter(Incident.Type=="Injury") %>%
filter(Status %in% c("Out", "As Tolerated")) %>%
filter(Result.of.Sport.Participation=="Yes") %>%
select(-Result.of.Sport.Participation)
incident_V <- subset(Incident_V,select=c("anon_id","Date","Sport", "Position", "Date.of.Injury...Onset.of.symptoms", "Side", "Body.Part.", "Total.Time.Injured", "Tissue.Type","OSICS14.Code","OSICS10.Diagnosis", "Final.Diagnosis", "Recurrence.of.Injury", "Injury.Prognosis", "General.mechanism","Specific.Mechanism","Injured.While.", "Month", "Year","Status", "Season.","Start.of.Status", "End.Date", "Total.Time.Injured"))
#52 +23 vars.
#Lower body injury binary
incident_V$LB.Injury <- ifelse(incident_V$Body.Part. %in% c("Thigh", "Ankle", "Lower leg", "Knee", "Foot", "Groin/hip"),1,0)
sum(incident_V$LB.Injury)
[1] 28
#ACL injury (most intense LB injury)
incident_V$ACL <- ifelse(incident_V$OSICS14.Code %in% c("KL1","KLA"),1,0)
sum(incident_V$ACL)
[1] 4
#HSI injury (overuse injury)
incident_V$HSI <- ifelse(incident_V$OSICS14.Code %in% c("TM1","TMB","TMS"),1,0)
sum(incident_V$HSI)
[1] 1
#1/16/24-9/8/24 (9 MONTHS)
#converting all dates
incident_v <- incident_V %>%
mutate(Total.Time.Injured = sum(Total.Time.Injured, na.rm = TRUE),
Date = as.Date(Date, format = '%m/%d/%Y'),
Start.of.Status=as.Date(Start.of.Status,format='%m/%d/%Y'),
End.Date= as.Date(End.Date, format='%m/%d/%Y'),
Date.of.Injury...Onset.of.symptoms= as.Date(Date.of.Injury...Onset.of.symptoms, format='%m/%d/%Y'),
Sport=case_when(
str_detect(Sport, "VOLLEYBALL")~ "Volleyball"
)
)
#create a length of status variable (Out, limited,as tolerated, full go)
incident_v$Length.of.Status <- difftime(incident_v$End.Date, incident_v$Start.of.Status,units=c("days"))
In womens’ volleyball 28 lower body injuries occurred, 4 of them
being ACL injuries, 1 of them being HSI injuries.
- Dynamo Dataset
#Dynamo (VALD) Basketball Data
#selects variables of interest
dynamo_B <- subset(Dynamo_B, select = c('anon_id', 'Date', 'Knee.Ex.Right.Side.Max.Force..N.', 'Knee.Ex.Left.Side.Max.Force..N.', 'Knee.Ex.Max.Force..N..Asymmetry', 'Knee.Ex.Right.Side.Avg.Force..N.', 'Knee.Ex.Left.Side.Avg.Force..N.', 'Knee.Ex.Avg.Force.Asymmetry', 'Knee.Ex.Right.Side.Max.Impulse..Ns.', 'Knee.Ex.Left.Side.Max.Impulse..Ns.', 'Knee.Ex.Max.Impulse.Asymmetry', 'Knee.Ex.Right.Side.Avg.Impulse..Ns.', 'Knee.Ex.Left.Side.Avg.Impulse..Ns.', 'Knee.Ex.Avg.Impulse.Asymmetry', 'Knee.Ex.Right.Side.Max.Rate.of.Force.Development..Ns.', 'Knee.Ex.Left.Side.Max.Rate.of.Force.Development..Ns.', 'Knee.Ex.Max.Rate.of.Force.Development.Asymmetry', 'Knee.Ex.Right.Side.Avg.Rate.of.Force.Development..Ns.', 'Knee.Ex.Left.Side.Avg.Rate.of.Force.Development..Ns.', 'Knee.Ex.Avg.Rate.of.Force.Development.Asymmetry'))
#converts the date to a date object and omits the NAs as well as calculating the Knee.Ex.Max.Force..N..Asymmetry variable for the missing values
dynamo_B <- dynamo_B %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y'),
Knee.Ex.Max.Force..N..Asymmetry = case_when(
Knee.Ex.Left.Side.Max.Force..N. > Knee.Ex.Right.Side.Max.Force..N. ~ round(100 * (1 - (Knee.Ex.Right.Side.Max.Force..N. / Knee.Ex.Left.Side.Max.Force..N.)), 1),
TRUE ~ Knee.Ex.Max.Force..N..Asymmetry
)) %>%
na.omit()
19 total observations, 3 with NA values in
Knee.Ex.Max.Force..N..Asymmetry.
#Dynamo (VALD) Soccer Data
#selects variables of interest
dynamo_S <- subset(Dynamo_S, select = c('anon_id', 'Date', 'Knee.Ex.Right.Side.Max.Force..N.', 'Knee.Ex.Left.Side.Max.Force..N.', 'Knee.Ex.Max.Force..N..Asymmetry', 'Knee.Ex.Right.Side.Avg.Force..N.', 'Knee.Ex.Left.Side.Avg.Force..N.', 'Knee.Ex.Avg.Force.Asymmetry', 'Knee.Ex.Right.Side.Max.Impulse..Ns.', 'Knee.Ex.Left.Side.Max.Impulse..Ns.', 'Knee.Ex.Max.Impulse.Asymmetry', 'Knee.Ex.Right.Side.Avg.Impulse..Ns.', 'Knee.Ex.Left.Side.Avg.Impulse..Ns.', 'Knee.Ex.Avg.Impulse.Asymmetry', 'Knee.Ex.Right.Side.Max.Rate.of.Force.Development..Ns.', 'Knee.Ex.Left.Side.Max.Rate.of.Force.Development..Ns.', 'Knee.Ex.Max.Rate.of.Force.Development.Asymmetry', 'Knee.Ex.Right.Side.Avg.Rate.of.Force.Development..Ns.', 'Knee.Ex.Left.Side.Avg.Rate.of.Force.Development..Ns.', 'Knee.Ex.Avg.Rate.of.Force.Development.Asymmetry'))
#converts the date to a date object and puts values from different observations together into one observation, then calculates the asymmetry statistics
dynamo_S <- dynamo_S %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y')) %>%
group_by(anon_id, Date) %>%
summarise(Knee.Ex.Right.Side.Max.Force..N. = sum(Knee.Ex.Right.Side.Max.Force..N., na.rm = TRUE),
Knee.Ex.Left.Side.Max.Force..N. = sum(Knee.Ex.Left.Side.Max.Force..N., na.rm = TRUE),
Knee.Ex.Max.Force..N..Asymmetry = sum(Knee.Ex.Max.Force..N..Asymmetry),
Knee.Ex.Right.Side.Avg.Force..N. = sum(Knee.Ex.Right.Side.Avg.Force..N., na.rm = TRUE),
Knee.Ex.Left.Side.Avg.Force..N. = sum(Knee.Ex.Left.Side.Avg.Force..N., na.rm = TRUE),
Knee.Ex.Avg.Force.Asymmetry = sum(Knee.Ex.Avg.Force.Asymmetry),
Knee.Ex.Right.Side.Max.Impulse..Ns. = sum(Knee.Ex.Right.Side.Max.Impulse..Ns., na.rm = TRUE),
Knee.Ex.Left.Side.Max.Impulse..Ns. = sum(Knee.Ex.Left.Side.Max.Impulse..Ns., na.rm = TRUE),
Knee.Ex.Max.Impulse.Asymmetry = sum(Knee.Ex.Max.Impulse.Asymmetry),
Knee.Ex.Right.Side.Avg.Impulse..Ns. = sum(Knee.Ex.Right.Side.Avg.Impulse..Ns., na.rm = TRUE),
Knee.Ex.Left.Side.Avg.Impulse..Ns. = sum(Knee.Ex.Left.Side.Avg.Impulse..Ns., na.rm = TRUE),
Knee.Ex.Avg.Impulse.Asymmetry = sum(Knee.Ex.Avg.Impulse.Asymmetry),
Knee.Ex.Right.Side.Max.Rate.of.Force.Development..Ns. = sum(Knee.Ex.Right.Side.Max.Rate.of.Force.Development..Ns., na.rm = TRUE),
Knee.Ex.Left.Side.Max.Rate.of.Force.Development..Ns. = sum(Knee.Ex.Left.Side.Max.Rate.of.Force.Development..Ns., na.rm = TRUE),
Knee.Ex.Max.Rate.of.Force.Development.Asymmetry = sum(Knee.Ex.Max.Rate.of.Force.Development.Asymmetry),
Knee.Ex.Right.Side.Avg.Rate.of.Force.Development..Ns. = sum(Knee.Ex.Right.Side.Avg.Rate.of.Force.Development..Ns., na.rm = TRUE),
Knee.Ex.Left.Side.Avg.Rate.of.Force.Development..Ns. = sum(Knee.Ex.Left.Side.Avg.Rate.of.Force.Development..Ns., na.rm = TRUE),
Knee.Ex.Avg.Rate.of.Force.Development.Asymmetry = sum(Knee.Ex.Avg.Rate.of.Force.Development.Asymmetry), .groups = "drop") %>%
mutate(Knee.Ex.Max.Force..N..Asymmetry = round(100 * (1 - (Knee.Ex.Left.Side.Max.Force..N. / Knee.Ex.Right.Side.Max.Force..N.)), 1),
Knee.Ex.Avg.Force.Asymmetry = round(100 * (1 - (Knee.Ex.Left.Side.Avg.Force..N. / Knee.Ex.Right.Side.Avg.Force..N.)), 1),
Knee.Ex.Max.Impulse.Asymmetry = round(100 * (1 - (Knee.Ex.Left.Side.Max.Impulse..Ns. / Knee.Ex.Right.Side.Max.Impulse..Ns.)), 1),
Knee.Ex.Avg.Impulse.Asymmetry = round(100 * (1 - (Knee.Ex.Left.Side.Avg.Impulse..Ns. / Knee.Ex.Right.Side.Avg.Impulse..Ns.)), 1),
Knee.Ex.Max.Rate.of.Force.Development.Asymmetry = round(100 * (1 - (Knee.Ex.Left.Side.Max.Rate.of.Force.Development..Ns. / Knee.Ex.Right.Side.Max.Rate.of.Force.Development..Ns.)), 1),
Knee.Ex.Avg.Rate.of.Force.Development.Asymmetry = round(100 * (1 - (Knee.Ex.Left.Side.Avg.Rate.of.Force.Development..Ns. / Knee.Ex.Right.Side.Avg.Rate.of.Force.Development..Ns.)), 1))
Only 1 observation, none of the asymmetry statistics are
summarized.
#Dynamo (VALD) Lacrosse Data
#selects variables of interest
dynamo_L <- subset(Dynamo_L, select = c('anon_id', 'Date', 'Knee.Ex.Right.Side.Max.Force..N.', 'Knee.Ex.Left.Side.Max.Force..N.', 'Knee.Ex.Max.Force..N..Asymmetry', 'Knee.Ex.Right.Side.Avg.Force..N.', 'Knee.Ex.Left.Side.Avg.Force..N.', 'Knee.Ex.Avg.Force.Asymmetry', 'Knee.Ex.Right.Side.Max.Impulse..Ns.', 'Knee.Ex.Left.Side.Max.Impulse..Ns.', 'Knee.Ex.Max.Impulse.Asymmetry', 'Knee.Ex.Right.Side.Avg.Impulse..Ns.', 'Knee.Ex.Left.Side.Avg.Impulse..Ns.', 'Knee.Ex.Avg.Impulse.Asymmetry', 'Knee.Ex.Right.Side.Max.Rate.of.Force.Development..Ns.', 'Knee.Ex.Left.Side.Max.Rate.of.Force.Development..Ns.', 'Knee.Ex.Max.Rate.of.Force.Development.Asymmetry', 'Knee.Ex.Right.Side.Avg.Rate.of.Force.Development..Ns.', 'Knee.Ex.Left.Side.Avg.Rate.of.Force.Development..Ns.', 'Knee.Ex.Avg.Rate.of.Force.Development.Asymmetry'))
#converts the date to a date object and omits the NAs as well as calculating the Knee.Ex.Max.Force..N..Asymmetry variable for the missing values
dynamo_L <- dynamo_L %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y'),
Knee.Ex.Max.Force..N..Asymmetry = case_when(
Knee.Ex.Left.Side.Max.Force..N. > Knee.Ex.Right.Side.Max.Force..N. ~ round(100 * (1 - (Knee.Ex.Right.Side.Max.Force..N. / Knee.Ex.Left.Side.Max.Force..N.)), 1),
TRUE ~ Knee.Ex.Max.Force..N..Asymmetry
)) %>%
na.omit()
38 total observations, 23 with NA values in
Knee.Ex.Max.Force..N..Asymmetry.
#Dynamo (VALD) Volleyball Data
#selects variables of interest
dynamo_V <- subset(Dynamo_V, select = c('anon_id', 'Date', 'Knee.Ex.Right.Side.Max.Force..N.', 'Knee.Ex.Left.Side.Max.Force..N.', 'Knee.Ex.Max.Force..N..Asymmetry', 'Knee.Ex.Right.Side.Avg.Force..N.', 'Knee.Ex.Left.Side.Avg.Force..N.', 'Knee.Ex.Avg.Force.Asymmetry', 'Knee.Ex.Right.Side.Max.Impulse..Ns.', 'Knee.Ex.Left.Side.Max.Impulse..Ns.', 'Knee.Ex.Max.Impulse.Asymmetry', 'Knee.Ex.Right.Side.Avg.Impulse..Ns.', 'Knee.Ex.Left.Side.Avg.Impulse..Ns.', 'Knee.Ex.Avg.Impulse.Asymmetry', 'Knee.Ex.Right.Side.Max.Rate.of.Force.Development..Ns.', 'Knee.Ex.Left.Side.Max.Rate.of.Force.Development..Ns.', 'Knee.Ex.Max.Rate.of.Force.Development.Asymmetry', 'Knee.Ex.Right.Side.Avg.Rate.of.Force.Development..Ns.', 'Knee.Ex.Left.Side.Avg.Rate.of.Force.Development..Ns.', 'Knee.Ex.Avg.Rate.of.Force.Development.Asymmetry'))
#converts the date to a date object and omits the NAs as well as calculating the Knee.Ex.Max.Force..N..Asymmetry variable for the missing values
dynamo_V <- dynamo_V %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y'),
Knee.Ex.Max.Force..N..Asymmetry = case_when(
Knee.Ex.Left.Side.Max.Force..N. > Knee.Ex.Right.Side.Max.Force..N. ~ round(100 * (1 - (Knee.Ex.Right.Side.Max.Force..N. / Knee.Ex.Left.Side.Max.Force..N.)), 1),
TRUE ~ Knee.Ex.Max.Force..N..Asymmetry
)) %>%
na.omit()
Only has 4 observations from one player.
- VALD- Forcedecks datasets #Forcedecks (VALD) basketball data
#1: TEST TYPE=CMJ
CMJ_B <- subset(Forcedecks_B, select = c("anon_id","Date","Position","Test.Type","Weight..kg.","Countermovement.Depth..cm.","Peak.Power...BM..W.kg.","Landing.RFD..N.s.", "Eccentric.Concentric.Mean.Force.Ratio", "Peak.Landing.Force..Asym...N.", "Peak.Power..W.","Concentric.Maximum.RFD..N.s.","Concentric.Maximum.RFD..Right...N.s.","Concentric.Maximum.RFD..Left...N.s.","Eccentric.Mean.Braking.Force..N.", "Max.Jump.Height..cm.", "Max.Concentric.Peak.Force..N.", "Relative.Concentric.Power.Bilateral","Relative.Eccentric.Power.Bilateral", "Max.Peak.Power...BM", "Max.Eccentric.Peak.Force..N.","Max.RSI.Modified.VALD","Max.Concentric.RPD..N.s.","Max.Concentric.Peak.Velocity..m.s.", "Max.Eccentric.Peak.Velocity..m.s.", "Max.Peak.Landing.Force..N.", "MAX.Concentric.Peak.Power..W.", "Max.CMJ.Jump.Height..cm.","Max.CMJ.RSI.Modified..m.s.", "Max.CMJ.Concentric.RPD..N.s.", "Max.CMJ.Peak.Power..W.", "Max.CMJ.Peak.Landing.Force..N.","CMJ.Concentric.Relative.Peak.Power...Difference.from.First","CMJ.Eccentric.Relative.Peak.Power...Difference.from.First","Eccentric.Asymmetry","Concentric.Asymmetry"
)) #2751 obs & 36 vars.
#possible other final dataset
cmj_b <- CMJ_B %>%
na.omit() #440 obs
#convert empty vectors to NA
CMJ_B[CMJ_B==""] <- NA #colSums(is.na(forcedecks_B)) look at NAs in columns
#to use in summarise
#function for mode
get_mode <- function(v) {
uniqv <- unique(v)
uniqv[which.max(tabulate(match(v, uniqv)))]
}
#set all needed variables to numeric
CMJ_B$Countermovement.Depth..cm. <- as.numeric(CMJ_B$Countermovement.Depth..cm.)
CMJ_B$Peak.Power...BM..W.kg. <- as.numeric(CMJ_B$Peak.Power...BM..W.kg.)
#combining values from different observations into one
CMJ_b <- CMJ_B %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y')) %>%
group_by(anon_id, Date,Test.Type) %>%
summarise(Weight..kg. = mean(Weight..kg., na.rm = TRUE),
Countermovement.Depth..cm.= mean(Countermovement.Depth..cm., na.rm=TRUE),
Peak.Power...BM..W.kg.= mean(Peak.Power...BM..W.kg., na.rm=TRUE),
Landing.RFD..N.s.= mean(Landing.RFD..N.s.,na.rm=TRUE),
Eccentric.Concentric.Mean.Force.Ratio= mean(Eccentric.Concentric.Mean.Force.Ratio,na.rm=TRUE),
Peak.Landing.Force..Asym...N.= mean(Peak.Landing.Force..Asym...N.,na.rm=TRUE),
Peak.Power..W.= mean(Peak.Power..W.,na.rm=TRUE),
Concentric.Maximum.RFD..N.s.= mean(Concentric.Maximum.RFD..N.s.,na.rm=TRUE),
Concentric.Maximum.RFD..Right...N.s.= mean(Concentric.Maximum.RFD..Right...N.s.,na.rm=TRUE),
Concentric.Maximum.RFD..Left...N.s.= mean(Concentric.Maximum.RFD..Left...N.s.,na.rm=TRUE),
Eccentric.Mean.Braking.Force..N.= mean(Eccentric.Mean.Braking.Force..N.,na.rm=TRUE),
Max.Jump.Height..cm.= mean(Max.Jump.Height..cm.,na.rm=TRUE),
Max.Concentric.Peak.Force..N.= mean(Max.Concentric.Peak.Force..N.,na.rm=TRUE),
Relative.Concentric.Power.Bilateral= mean(Relative.Concentric.Power.Bilateral,na.rm=TRUE),
Relative.Eccentric.Power.Bilateral= mean(Relative.Eccentric.Power.Bilateral,na.rm=TRUE),
Max.Peak.Power...BM= mean(Max.Peak.Power...BM,na.rm=TRUE),
Max.Eccentric.Peak.Force..N.= mean(Max.Eccentric.Peak.Force..N.,na.rm=TRUE),
Max.RSI.Modified.VALD= mean(Max.RSI.Modified.VALD,na.rm=TRUE),
Max.Concentric.RPD..N.s.= mean(Max.Concentric.RPD..N.s.,na.rm=TRUE),
Max.Concentric.Peak.Velocity..m.s.= mean(Max.Concentric.Peak.Velocity..m.s.,na.rm=TRUE),
Max.Eccentric.Peak.Velocity..m.s.= mean(Max.Eccentric.Peak.Velocity..m.s.,na.rm=TRUE),
Max.Peak.Landing.Force..N.= mean(Max.Peak.Landing.Force..N.,na.rm=TRUE),
MAX.Concentric.Peak.Power..W.= mean(MAX.Concentric.Peak.Power..W.,na.rm=TRUE),
Max.CMJ.Jump.Height..cm.= mean(Max.CMJ.Jump.Height..cm.,na.rm=TRUE),
Max.CMJ.RSI.Modified..m.s.= mean(Max.CMJ.RSI.Modified..m.s.,na.rm=TRUE),
Max.CMJ.Concentric.RPD..N.s.= mean(Max.CMJ.Concentric.RPD..N.s.,na.rm=TRUE),
Max.CMJ.Peak.Power..W.= mean(Max.CMJ.Peak.Power..W.,na.rm=TRUE),
Max.CMJ.Peak.Landing.Force..N.= mean(Max.CMJ.Peak.Landing.Force..N.,na.rm=TRUE),
CMJ.Concentric.Relative.Peak.Power...Difference.from.First= mean(CMJ.Concentric.Relative.Peak.Power...Difference.from.First,na.rm=TRUE),
CMJ.Eccentric.Relative.Peak.Power...Difference.from.First= mean(CMJ.Eccentric.Relative.Peak.Power...Difference.from.First,na.rm=TRUE),
Position= get_mode(Position),
Eccentric.Asymmetry= get_mode(Eccentric.Asymmetry),
Concentric.Asymmetry= get_mode(Concentric.Asymmetry),
.groups = 'drop'
) #1393 obs & 36 vars
#fix NaN values
CMJ_bb <- CMJ_b %>%
na.omit() #196 obs & 36 vars
#selects counter movement jumps another way with normative information
b <- Forcedecks_B %>%
filter(Test.Type == 'CMJ') %>%
dplyr::select("anon_id","Date","Position","Test.Type","Countermovement.Depth..cm.","Peak.Power...BM..W.kg.","Landing.RFD..N.s.", "Eccentric.Concentric.Mean.Force.Ratio", "Peak.Landing.Force..Asym...N.", "Peak.Power..W.", "Concentric.RFD..N.s.", "Concentric.RFD..Left...N.s.","Concentric.RFD..Right...N.s.", "Concentric.Time.to.Peak.Force..s.", "Eccentric.Mean.Braking.Force..N.", "Landing.Net.Peak.Force...BM..N.kg.", "Peak.Net.Takeoff.Force...BM..N.kg.", "Concentric.RPD...BM..W.s.kg.", "Force.at.Peak.Power..N.", "Eccentric.Mean.Deceleration.Force..N.", "Eccentric.Peak.Force..N.", "RSI.Modified..m.s.", "CMJ.Stiffness..Left...N.m.", "CMJ.Stiffness..Right...N.m.", "Eccentric.Asymmetry","Concentric.Asymmetry", "Peak.Landing.Asymmetry", "DSI", "DSI.Bucket", "Eccentric.Peak.Power...BM..W.kg.", "Jump.Height..Imp.Mom...cm.", "Eccentric.Duration..s.", "Eccentric.Deceleration.Impulse..Ns.") %>%
na.omit()
#calculates differences from norm and makes Date a date object
b <- b %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y'),
RSI.Modified..m.s. = RSI.Modified..m.s. / 100,
RSI.Modified.Diff.Norm = (RSI.Modified..m.s. - 0.417) / 0.417,
Ecc.Peak.Power.Rel.Diff.Norm = (Eccentric.Peak.Power...BM..W.kg. - 18) / 18,
Jump.Heigh.Diff.Norm = (Jump.Height..Imp.Mom...cm. - 30) / 30,
Ecc.Duration.Diff.Norm = (Eccentric.Duration..s. - 0.51) / 0.51,
Ecc.Deceleration.Impulse.Diff.Norm = (Eccentric.Deceleration.Impulse..Ns. - 98.4) / 98.4,
Sport = 'Basketball'
) #442 obs and 39 vars
#2 TEST TYPE=HJ
HJ_B <- Forcedecks_B %>%
filter(Test.Type=="HJ") %>% #424 obs
dplyr::select("anon_id", "Date", "Corrected.Standing.Weight..Kg.", "Mean.RSI..Flight.Contact.Time.", "Active.Stiffness..N.m.", "Best.Average.Force..N.", "Best.Average.Force..Asym...N.", "Best.Time.to.Peak.Force..ms.", "Best.Contact.Time..ms.", "Best.Flight.Time..ms.", "Best.Impulse..N.s.", "Best.Peak.Force..N.", "Best.Peak.Force..Asym...N.", "Mean.Average.Force..N.", "Mean.Average.Force..Asym...N.", "Mean.Landing.RFD..N.s.", "Mean.Landing.RFD..Asym...N.s.", "Stiffness.Fatigue....", "Stiffness.Fatigue..Asym.....", "Max.Jump.Height..cm.", "HJ.RSI", "Mean.Flight.Time..ms.", "Mean.Contact.Time..ms.") %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y')) %>%
na.omit() %>%
mutate(Sport = 'Basketball')
#409 obs & 20 vars
#3: TEST TYPE= IMTP
IMTP_B <- Forcedecks_B %>%
filter(Test.Type=="IMTP") %>% #162
select("anon_id", "Date", "Baseline.Force..N.","Baseline.Force..Asym...N.", "Peak.Vertical.Force..N.", "Peak.Vertical.Force...BM..N.kg.", "Peak.Vertical.Force..Asym...N.", "RFD...50ms..N.s.", "RFD...50ms..Asym...N.s.", "RFD...100ms..N.s.", "RFD...100ms..Asym...N.s.", "RFD...150ms..N.s.", "RFD...150ms..Asym...N.s.", "RFD...200ms..N.s.", "RFD...200ms..Asym...N.s.", "Net.Peak.Vertical.Force..N.s.", "Net.Peak.Vertical.Force..Asym...N.s.", "Force.at.200ms...BM..N.kg.", "Eccentric.Asymmetry", "Concentric.Asymmetry","MEAN.Eccentric.Mean.Force.Left", "MEAN.Eccentric.Mean.Force.Right", "MEAN.Concentric.Mean.Force.Left", "MEAN.Concentric.Mean.Force.Right", "MEAN.Concentric.Mean.Force.Asym", "MEAN.Peak.Landing.Force.Asym", "MEAN.Relative.Peak.Power", "MEAN.CMJ.Concentric.Force", "MEAN.Peak.Landing.Force.Left", "MEAN.Peak.Landing.Force.Right", "DSI", "DSI.Bucket") %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y')) %>%
na.omit() %>%
mutate(Sport = 'Basketball') #50 obs & 32 vars
#Forcedecks (VALD) Soccer Data
#1: TEST TYPE==CMJ
#selects variables of interest
CMJ_S <- subset(Forcedecks_S, select = c("anon_id","Date","Position","Test.Type","Weight..kg.","Countermovement.Depth..cm.","Peak.Power...BM..W.kg.","Landing.RFD..N.s.", "Eccentric.Concentric.Mean.Force.Ratio", "Peak.Landing.Force..Asym...N.", "Peak.Power..W.","Concentric.Maximum.RFD..N.s.","Concentric.Maximum.RFD..Right...N.s.","Concentric.Maximum.RFD..Left...N.s.","Eccentric.Mean.Braking.Force..N.", "Max.Jump.Height..cm.", "Max.Concentric.Peak.Force..N.", "Relative.Concentric.Power.Bilateral",
"Relative.Eccentric.Power.Bilateral","Max.Peak.Power...BM", "Max.Eccentric.Peak.Force..N.",
"Max.RSI.Modified.VALD","Max.Concentric.RPD..N.s.", "Max.Concentric.Peak.Velocity..m.s.", "Max.Eccentric.Peak.Velocity..m.s.", "Max.Peak.Landing.Force..N.", "MAX.Concentric.Peak.Power..W.","Max.CMJ.Jump.Height..cm.",
"Max.CMJ.RSI.Modified..m.s.","Max.CMJ.Concentric.RPD..N.s.","Max.CMJ.Peak.Power..W.","Max.CMJ.Peak.Landing.Force..N.","CMJ.Concentric.Relative.Peak.Power...Difference.from.First","CMJ.Eccentric.Relative.Peak.Power...Difference.from.First","Eccentric.Asymmetry","Concentric.Asymmetry"
)) #3443 obs & 36 vars
#OTHER POSSIBLE FINAL DATASET
cmj_s <- CMJ_S %>%
na.omit() #562 obs & 36 vars
cmj_s[cmj_s==""] <- NA
CMJ_S[CMJ_S==""] <- NA
#combining values from different observations into one
CMJ_s <- CMJ_S %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y')) %>%
group_by(anon_id, Date, Test.Type) %>%
summarise(Weight..kg. = mean(Weight..kg., na.rm = TRUE),
Countermovement.Depth..cm.= mean(Countermovement.Depth..cm., na.rm=TRUE),
Peak.Power...BM..W.kg.= mean(Peak.Power...BM..W.kg., na.rm=TRUE),
Landing.RFD..N.s.= mean(Landing.RFD..N.s.,na.rm=TRUE),
Eccentric.Concentric.Mean.Force.Ratio= mean(Eccentric.Concentric.Mean.Force.Ratio,na.rm=TRUE),
Peak.Landing.Force..Asym...N.= mean(Peak.Landing.Force..Asym...N.,na.rm=TRUE),
Peak.Power..W.= mean(Peak.Power..W.,na.rm=TRUE),
Concentric.Maximum.RFD..N.s.= mean(Concentric.Maximum.RFD..N.s.,na.rm=TRUE),
Concentric.Maximum.RFD..Right...N.s.= mean(Concentric.Maximum.RFD..Right...N.s.,na.rm=TRUE),
Concentric.Maximum.RFD..Left...N.s.= mean(Concentric.Maximum.RFD..Left...N.s.,na.rm=TRUE),
Eccentric.Mean.Braking.Force..N.= mean(Eccentric.Mean.Braking.Force..N.,na.rm=TRUE),
Max.Jump.Height..cm.= mean(Max.Jump.Height..cm.,na.rm=TRUE),
Max.Concentric.Peak.Force..N.= mean(Max.Concentric.Peak.Force..N.,na.rm=TRUE),
Relative.Concentric.Power.Bilateral= mean(Relative.Concentric.Power.Bilateral,na.rm=TRUE),
Relative.Eccentric.Power.Bilateral= mean(Relative.Eccentric.Power.Bilateral,na.rm=TRUE),
Max.Peak.Power...BM= mean(Max.Peak.Power...BM,na.rm=TRUE),
Max.Eccentric.Peak.Force..N.= mean(Max.Eccentric.Peak.Force..N.,na.rm=TRUE),
Max.RSI.Modified.VALD= mean(Max.RSI.Modified.VALD,na.rm=TRUE),
Max.Concentric.RPD..N.s.= mean(Max.Concentric.RPD..N.s.,na.rm=TRUE),
Max.Concentric.Peak.Velocity..m.s.= mean(Max.Concentric.Peak.Velocity..m.s.,na.rm=TRUE),
Max.Eccentric.Peak.Velocity..m.s.= mean(Max.Eccentric.Peak.Velocity..m.s.,na.rm=TRUE),
Max.Peak.Landing.Force..N.= mean(Max.Peak.Landing.Force..N.,na.rm=TRUE),
MAX.Concentric.Peak.Power..W.= mean(MAX.Concentric.Peak.Power..W.,na.rm=TRUE),
Max.CMJ.Jump.Height..cm.= mean(Max.CMJ.Jump.Height..cm.,na.rm=TRUE),
Max.CMJ.RSI.Modified..m.s.= mean(Max.CMJ.RSI.Modified..m.s.,na.rm=TRUE),
Max.CMJ.Concentric.RPD..N.s.= mean(Max.CMJ.Concentric.RPD..N.s.,na.rm=TRUE),
Max.CMJ.Peak.Power..W.= mean(Max.CMJ.Peak.Power..W.,na.rm=TRUE),
Max.CMJ.Peak.Landing.Force..N.= mean(Max.CMJ.Peak.Landing.Force..N.,na.rm=TRUE),
CMJ.Concentric.Relative.Peak.Power...Difference.from.First= mean(CMJ.Concentric.Relative.Peak.Power...Difference.from.First,na.rm=TRUE),
CMJ.Eccentric.Relative.Peak.Power...Difference.from.First= mean(CMJ.Eccentric.Relative.Peak.Power...Difference.from.First,na.rm=TRUE),
Position= get_mode(Position),
Eccentric.Asymmetry= get_mode(Eccentric.Asymmetry),
Concentric.Asymmetry= get_mode(Concentric.Asymmetry),
.groups = 'drop'
) # 1077 obs & 32 vars -> 1571
CMJ_soc <- CMJ_s %>%
na.omit() #621 obs & 32 vars -> 600 -> 257 obs & 36 vars
#selects counter movement jumps another way with normative information
s <- Forcedecks_S %>%
filter(Test.Type == 'CMJ') %>%
dplyr::select("anon_id","Date","Position","Test.Type","Countermovement.Depth..cm.","Peak.Power...BM..W.kg.","Landing.RFD..N.s.", "Eccentric.Concentric.Mean.Force.Ratio", "Peak.Landing.Force..Asym...N.", "Peak.Power..W.", "Concentric.RFD..N.s.", "Concentric.RFD..Left...N.s.","Concentric.RFD..Right...N.s.", "Concentric.Time.to.Peak.Force..s.", "Eccentric.Mean.Braking.Force..N.", "Landing.Net.Peak.Force...BM..N.kg.", "Peak.Net.Takeoff.Force...BM..N.kg.", "Concentric.RPD...BM..W.s.kg.", "Force.at.Peak.Power..N.", "Eccentric.Mean.Deceleration.Force..N.", "Eccentric.Peak.Force..N.", "RSI.Modified..m.s.", "CMJ.Stiffness..Left...N.m.", "CMJ.Stiffness..Right...N.m.", "Eccentric.Asymmetry","Concentric.Asymmetry", "Peak.Landing.Asymmetry", "DSI", "DSI.Bucket", "Eccentric.Peak.Power...BM..W.kg.", "Jump.Height..Imp.Mom...cm.", "Eccentric.Duration..s.", "Eccentric.Deceleration.Impulse..Ns.") %>%
na.omit()
#calculates differences from norm and makes Date a date object
s <- s %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y'),
RSI.Modified..m.s. = RSI.Modified..m.s. / 100,
RSI.Modified.Diff.Norm = (RSI.Modified..m.s. - 0.416) / 0.416,
Ecc.Peak.Power.Rel.Diff.Norm = (Eccentric.Peak.Power...BM..W.kg. - 18) / 18,
Jump.Heigh.Diff.Norm = (Jump.Height..Imp.Mom...cm. - 30) / 30,
Ecc.Duration.Diff.Norm = (Eccentric.Duration..s. - 0.49) / 0.49,
Ecc.Deceleration.Impulse.Diff.Norm = (Eccentric.Deceleration.Impulse..Ns. - 81.5) / 81.5,
Sport = 'Soccer'
)
#2 TEST TYPE= HJ
HJ_S <- Forcedecks_S %>%
filter(Test.Type=="HJ") %>% #575 obs
dplyr::select("anon_id", "Date", "Corrected.Standing.Weight..Kg.", "Mean.RSI..Flight.Contact.Time.", "Active.Stiffness..N.m.", "Best.Average.Force..N.", "Best.Average.Force..Asym...N.", "Best.Time.to.Peak.Force..ms.", "Best.Contact.Time..ms.", "Best.Flight.Time..ms.", "Best.Impulse..N.s.", "Best.Peak.Force..N.", "Best.Peak.Force..Asym...N.", "Mean.Average.Force..N.", "Mean.Average.Force..Asym...N.", "Mean.Landing.RFD..N.s.", "Mean.Landing.RFD..Asym...N.s.", "Stiffness.Fatigue....", "Stiffness.Fatigue..Asym.....", "Max.Jump.Height..cm.", "HJ.RSI", "Mean.Flight.Time..ms.", "Mean.Contact.Time..ms.") %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y')) %>%
na.omit() %>%
mutate(Sport = 'Basketball')
#556 obs & 20 vars
#3 TEST TYPE- SLJ
SLJ_S <- Forcedecks_S %>%
filter(Test.Type=="SLJ") # 455 obs
#important variables
SLJ_S <- subset(SLJ_S, select = c("anon_id", "Date", "Position", "Weight..kg.", "Jump.Height..Flight.Time...cm.", "Jump.Height..Imp.Mom...cm.", "Max.Jump.Height..cm.", "Max.Single.Leg.Jump.Height.Left", "Max.Single.Leg.Jump.Height.Right", "First.SLJ.Jump.Height", "Max.Concentric.Peak.Velocity..m.s.", "Max.Eccentric.Peak.Velocity..m.s.", "RSI.Modified..m.s.", "Max.RSI.Modified..m.s.", "Max.RSI.Modified.VALD", "Eccentric.Mean.Braking.Force..N.", "Landing.RFD..N.s.","Concentric.Maximum.RFD..N.s.", "Concentric.Maximum.RFD..Right...N.s.","Concentric.Maximum.RFD..Left...N.s.", "Concentric.Impulse..Ns.", "Concentric.Impulse..Left...Ns.", "Concentric.Impulse..Right...Ns.", "Max.Concentric.Peak.Force..N.", "Max.Eccentric.Peak.Force..N."
)) #455 obs & 25 vars
SLJ_S[SLJ_S==""] <- NA
#combining values from different observations into one
SLJ_s <- SLJ_S %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y')) %>%
group_by(anon_id, Date) %>%
summarise(Weight..kg. = mean(Weight..kg., na.rm = TRUE),
Jump.Height..Flight.Time...cm.= mean(Jump.Height..Flight.Time...cm., na.rm=TRUE),
Jump.Height..Imp.Mom...cm.= mean(Jump.Height..Imp.Mom...cm.,na.rm=TRUE),
Max.Jump.Height..cm.= mean(Max.Jump.Height..cm. ,na.rm=TRUE),
Max.Single.Leg.Jump.Height.Left= mean(Max.Single.Leg.Jump.Height.Left ,na.rm=TRUE),
Max.Single.Leg.Jump.Height.Right= mean(Max.Single.Leg.Jump.Height.Right ,na.rm=TRUE),
First.SLJ.Jump.Height= mean(First.SLJ.Jump.Height, na.rm=TRUE),
Max.Concentric.Peak.Velocity..m.s.= mean(Max.Concentric.Peak.Velocity..m.s., na.rm=TRUE),
Max.Eccentric.Peak.Velocity..m.s.= mean(Max.Eccentric.Peak.Velocity..m.s., na.rm=TRUE),
RSI.Modified..m.s.= mean(RSI.Modified..m.s., na.rm=TRUE),
Max.RSI.Modified..m.s.= mean(Max.RSI.Modified..m.s., na.rm=TRUE),
Max.RSI.Modified.VALD= mean(Max.RSI.Modified.VALD, na.rm=TRUE),
Eccentric.Mean.Braking.Force..N.= mean(Eccentric.Mean.Braking.Force..N., na.rm=TRUE),
Landing.RFD..N.s.= mean(Landing.RFD..N.s., na.rm=TRUE),
Concentric.Maximum.RFD..N.s.= mean(Concentric.Maximum.RFD..N.s., na.rm=TRUE),
Concentric.Maximum.RFD..Right...N.s.= mean(Concentric.Maximum.RFD..Right...N.s.,na.rm=TRUE),
Concentric.Maximum.RFD..Left...N.s.= mean(Concentric.Maximum.RFD..Left...N.s.,na.rm=TRUE),
Concentric.Impulse..Ns.= mean(Concentric.Impulse..Ns.,na.rm=TRUE),
Concentric.Impulse..Left...Ns.= mean(Concentric.Impulse..Left...Ns.,na.rm=TRUE),
Concentric.Impulse..Right...Ns.= mean(Concentric.Impulse..Right...Ns.,na.rm=TRUE),
Max.Concentric.Peak.Force..N.= mean(Max.Concentric.Peak.Force..N.,na.rm=TRUE),
Max.Eccentric.Peak.Force..N.= mean(Max.Eccentric.Peak.Force..N.,na.rm=TRUE),
Position= get_mode(Position),
.groups = 'drop'
) #83 obs 25 vars
#4 TEST TYPE- IMTP
IMTP_S <- Forcedecks_S %>%
filter(Test.Type=="IMTP") %>% #200 obs
select("anon_id", "Date", "Baseline.Force..N.","Baseline.Force..Asym...N.", "Peak.Vertical.Force..N.", "Peak.Vertical.Force...BM..N.kg.", "Peak.Vertical.Force..Asym...N.", "RFD...50ms..N.s.", "RFD...50ms..Asym...N.s.", "RFD...100ms..N.s.", "RFD...100ms..Asym...N.s.", "RFD...150ms..N.s.", "RFD...150ms..Asym...N.s.", "RFD...200ms..N.s.", "RFD...200ms..Asym...N.s.", "Net.Peak.Vertical.Force..N.s.", "Net.Peak.Vertical.Force..Asym...N.s.", "Force.at.200ms...BM..N.kg.", "Eccentric.Asymmetry", "Concentric.Asymmetry","MEAN.Eccentric.Mean.Force.Left", "MEAN.Eccentric.Mean.Force.Right", "MEAN.Concentric.Mean.Force.Left", "MEAN.Concentric.Mean.Force.Right", "MEAN.Concentric.Mean.Force.Asym", "MEAN.Peak.Landing.Force.Asym", "MEAN.Relative.Peak.Power", "MEAN.CMJ.Concentric.Force", "MEAN.Peak.Landing.Force.Left", "MEAN.Peak.Landing.Force.Right", "DSI", "DSI.Bucket") %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y')) %>%
na.omit() %>%
mutate(Sport = 'Basketball') #68 obs & 30 vars
#Forcedecks (VALD) Lacrosse Data
#1 : TEST TYPE= CMJ
#selects variables of interest
CMJ_L <- subset(Forcedecks_L, select = c("anon_id","Date","Position","Test.Type","Weight..kg.","Countermovement.Depth..cm.","Peak.Power...BM..W.kg.","Landing.RFD..N.s.", "Eccentric.Concentric.Mean.Force.Ratio", "Peak.Landing.Force..Asym...N.", "Peak.Power..W.","Concentric.Maximum.RFD..N.s.","Concentric.Maximum.RFD..Right...N.s.","Concentric.Maximum.RFD..Left...N.s.","Eccentric.Mean.Braking.Force..N.", "Max.Jump.Height..cm.", "Max.Concentric.Peak.Force..N.", "Relative.Concentric.Power.Bilateral",
"Relative.Eccentric.Power.Bilateral","Max.Peak.Power...BM", "Max.Eccentric.Peak.Force..N.",
"Max.RSI.Modified.VALD","Max.Concentric.RPD..N.s.", "Max.Concentric.Peak.Velocity..m.s.", "Max.Eccentric.Peak.Velocity..m.s.", "Max.Peak.Landing.Force..N.", "MAX.Concentric.Peak.Power..W.","Max.CMJ.Jump.Height..cm.",
"Max.CMJ.RSI.Modified..m.s.","Max.CMJ.Concentric.RPD..N.s.","Max.CMJ.Peak.Power..W.","Max.CMJ.Peak.Landing.Force..N.","CMJ.Concentric.Relative.Peak.Power...Difference.from.First","CMJ.Eccentric.Relative.Peak.Power...Difference.from.First","Eccentric.Asymmetry","Concentric.Asymmetry"
)) #1939 obs & 36 vars
#possible other final dataset
cmj_l <- CMJ_L %>%
na.omit() #377 obs
CMJ_L[CMJ_L==""] <- NA
#combining values from different observations into one
CMJ_l <- CMJ_L %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y')) %>%
group_by(anon_id, Date, Test.Type) %>%
summarise(Weight..kg. = mean(Weight..kg., na.rm = TRUE),
Countermovement.Depth..cm.= mean(Countermovement.Depth..cm., na.rm=TRUE),
Peak.Power...BM..W.kg.= mean(Peak.Power...BM..W.kg., na.rm=TRUE),
Landing.RFD..N.s.= mean(Landing.RFD..N.s.,na.rm=TRUE),
Eccentric.Concentric.Mean.Force.Ratio= mean(Eccentric.Concentric.Mean.Force.Ratio,na.rm=TRUE),
Peak.Landing.Force..Asym...N.= mean(Peak.Landing.Force..Asym...N.,na.rm=TRUE),
Peak.Power..W.= mean(Peak.Power..W.,na.rm=TRUE),
Concentric.Maximum.RFD..N.s.= mean(Concentric.Maximum.RFD..N.s.,na.rm=TRUE),
Concentric.Maximum.RFD..Right...N.s.= mean(Concentric.Maximum.RFD..Right...N.s.,na.rm=TRUE),
Concentric.Maximum.RFD..Left...N.s.= mean(Concentric.Maximum.RFD..Left...N.s.,na.rm=TRUE),
Eccentric.Mean.Braking.Force..N.= mean(Eccentric.Mean.Braking.Force..N.,na.rm=TRUE),
Max.Jump.Height..cm.= mean(Max.Jump.Height..cm.,na.rm=TRUE),
Max.Concentric.Peak.Force..N.= mean(Max.Concentric.Peak.Force..N.,na.rm=TRUE),
Relative.Concentric.Power.Bilateral= mean(Relative.Concentric.Power.Bilateral,na.rm=TRUE),
Relative.Eccentric.Power.Bilateral= mean(Relative.Eccentric.Power.Bilateral,na.rm=TRUE),
Max.Peak.Power...BM= mean(Max.Peak.Power...BM,na.rm=TRUE),
Max.Eccentric.Peak.Force..N.= mean(Max.Eccentric.Peak.Force..N.,na.rm=TRUE),
Max.RSI.Modified.VALD= mean(Max.RSI.Modified.VALD,na.rm=TRUE),
Max.Concentric.RPD..N.s.= mean(Max.Concentric.RPD..N.s.,na.rm=TRUE),
Max.Concentric.Peak.Velocity..m.s.= mean(Max.Concentric.Peak.Velocity..m.s.,na.rm=TRUE),
Max.Eccentric.Peak.Velocity..m.s.= mean(Max.Eccentric.Peak.Velocity..m.s.,na.rm=TRUE),
Max.Peak.Landing.Force..N.= mean(Max.Peak.Landing.Force..N.,na.rm=TRUE),
MAX.Concentric.Peak.Power..W.= mean(MAX.Concentric.Peak.Power..W.,na.rm=TRUE),
Max.CMJ.Jump.Height..cm.= mean(Max.CMJ.Jump.Height..cm.,na.rm=TRUE),
Max.CMJ.RSI.Modified..m.s.= mean(Max.CMJ.RSI.Modified..m.s.,na.rm=TRUE),
Max.CMJ.Concentric.RPD..N.s.= mean(Max.CMJ.Concentric.RPD..N.s.,na.rm=TRUE),
Max.CMJ.Peak.Power..W.= mean(Max.CMJ.Peak.Power..W.,na.rm=TRUE),
Max.CMJ.Peak.Landing.Force..N.= mean(Max.CMJ.Peak.Landing.Force..N.,na.rm=TRUE),
CMJ.Concentric.Relative.Peak.Power...Difference.from.First= mean(CMJ.Concentric.Relative.Peak.Power...Difference.from.First,na.rm=TRUE),
CMJ.Eccentric.Relative.Peak.Power...Difference.from.First= mean(CMJ.Eccentric.Relative.Peak.Power...Difference.from.First,na.rm=TRUE),
Position= get_mode(Position),
Eccentric.Asymmetry= get_mode(Eccentric.Asymmetry),
Concentric.Asymmetry= get_mode(Concentric.Asymmetry),
.groups = 'drop'
) # 1238 obs & 36 vars
CMJ_lax <- CMJ_l %>%
na.omit() #277 obs & 36 vars
#selects counter movement jumps another way with normative information
l <- Forcedecks_L %>%
filter(Test.Type == 'CMJ') %>%
dplyr::select("anon_id","Date","Position","Test.Type","Countermovement.Depth..cm.","Peak.Power...BM..W.kg.","Landing.RFD..N.s.", "Eccentric.Concentric.Mean.Force.Ratio", "Peak.Landing.Force..Asym...N.", "Peak.Power..W.", "Concentric.RFD..N.s.", "Concentric.RFD..Left...N.s.","Concentric.RFD..Right...N.s.", "Concentric.Time.to.Peak.Force..s.", "Eccentric.Mean.Braking.Force..N.", "Landing.Net.Peak.Force...BM..N.kg.", "Peak.Net.Takeoff.Force...BM..N.kg.", "Concentric.RPD...BM..W.s.kg.", "Force.at.Peak.Power..N.", "Eccentric.Mean.Deceleration.Force..N.", "Eccentric.Peak.Force..N.", "RSI.Modified..m.s.", "CMJ.Stiffness..Left...N.m.", "CMJ.Stiffness..Right...N.m.", "Eccentric.Asymmetry","Concentric.Asymmetry", "Peak.Landing.Asymmetry", "DSI", "DSI.Bucket", "Eccentric.Peak.Power...BM..W.kg.", "Jump.Height..Imp.Mom...cm.", "Eccentric.Duration..s.", "Eccentric.Deceleration.Impulse..Ns.") %>%
na.omit()
#calculates differences from norm and makes Date a date object
l <- l %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y'),
RSI.Modified..m.s. = RSI.Modified..m.s. / 100,
RSI.Modified.Diff.Norm = (RSI.Modified..m.s. - 0.359) / 0.359,
Ecc.Peak.Power.Rel.Diff.Norm = (Eccentric.Peak.Power...BM..W.kg. - 16) / 16,
Jump.Heigh.Diff.Norm = (Jump.Height..Imp.Mom...cm. - 29) / 29,
Ecc.Duration.Diff.Norm = (Eccentric.Duration..s. - 0.55) / 0.55,
Ecc.Deceleration.Impulse.Diff.Norm = (Eccentric.Deceleration.Impulse..Ns. - 81.5) / 81.5,
Sport = 'Lacrosse'
)
#2: TEST TYPE= HJ
HJ_L <- Forcedecks_L %>%
filter(Test.Type=="HJ") %>% #582 obs
dplyr::select("anon_id", "Date", "Corrected.Standing.Weight..Kg.", "Mean.RSI..Flight.Contact.Time.", "Active.Stiffness..N.m.", "Best.Average.Force..N.", "Best.Average.Force..Asym...N.", "Best.Time.to.Peak.Force..ms.", "Best.Contact.Time..ms.", "Best.Flight.Time..ms.", "Best.Impulse..N.s.", "Best.Peak.Force..N.", "Best.Peak.Force..Asym...N.", "Mean.Average.Force..N.", "Mean.Average.Force..Asym...N.", "Mean.Landing.RFD..N.s.", "Mean.Landing.RFD..Asym...N.s.", "Stiffness.Fatigue....", "Stiffness.Fatigue..Asym.....", "Max.Jump.Height..cm.", "HJ.RSI", "Mean.Flight.Time..ms.", "Mean.Contact.Time..ms.") %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y')) %>%
na.omit() %>%
mutate(Sport = 'Basketball')
#573 obs & 20 vars
#3: TEST TYPE: SLJ
SLJ_L <- Forcedecks_L %>%
filter(Test.Type=="SLJ") #190 obs
#important variables
SLJ_L <- subset(SLJ_L, select = c("anon_id", "Date", "Position", "Weight..kg.", "Jump.Height..Flight.Time...cm.", "Jump.Height..Imp.Mom...cm.", "Max.Jump.Height..cm.", "Max.Single.Leg.Jump.Height.Left", "Max.Single.Leg.Jump.Height.Right", "First.SLJ.Jump.Height", "Max.Concentric.Peak.Velocity..m.s.", "Max.Eccentric.Peak.Velocity..m.s.", "RSI.Modified..m.s.", "Max.RSI.Modified..m.s.", "Max.RSI.Modified.VALD", "Eccentric.Mean.Braking.Force..N.", "Landing.RFD..N.s.","Concentric.Maximum.RFD..N.s.", "Concentric.Maximum.RFD..Right...N.s.","Concentric.Maximum.RFD..Left...N.s.", "Concentric.Impulse..Ns.", "Concentric.Impulse..Left...Ns.", "Concentric.Impulse..Right...Ns.", "Max.Concentric.Peak.Force..N.", "Max.Eccentric.Peak.Force..N."
)) #190 obs & 25 vars
SLJ_L[SLJ_L==""] <- NA
#combining values from different observations into one
SLJ_l <- SLJ_L %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y')) %>%
group_by(anon_id, Date) %>%
summarise(Weight..kg. = mean(Weight..kg., na.rm = TRUE),
Jump.Height..Flight.Time...cm.= mean(Jump.Height..Flight.Time...cm., na.rm=TRUE),
Jump.Height..Imp.Mom...cm.= mean(Jump.Height..Imp.Mom...cm.,na.rm=TRUE),
Max.Jump.Height..cm.= mean(Max.Jump.Height..cm. ,na.rm=TRUE),
Max.Single.Leg.Jump.Height.Left= mean(Max.Single.Leg.Jump.Height.Left ,na.rm=TRUE),
Max.Single.Leg.Jump.Height.Right= mean(Max.Single.Leg.Jump.Height.Right ,na.rm=TRUE),
First.SLJ.Jump.Height= mean(First.SLJ.Jump.Height, na.rm=TRUE),
Max.Concentric.Peak.Velocity..m.s.= mean(Max.Concentric.Peak.Velocity..m.s., na.rm=TRUE),
Max.Eccentric.Peak.Velocity..m.s.= mean(Max.Eccentric.Peak.Velocity..m.s., na.rm=TRUE),
RSI.Modified..m.s.= mean(RSI.Modified..m.s., na.rm=TRUE),
Max.RSI.Modified..m.s.= mean(Max.RSI.Modified..m.s., na.rm=TRUE),
Max.RSI.Modified.VALD= mean(Max.RSI.Modified.VALD, na.rm=TRUE),
Eccentric.Mean.Braking.Force..N.= mean(Eccentric.Mean.Braking.Force..N., na.rm=TRUE),
Landing.RFD..N.s.= mean(Landing.RFD..N.s., na.rm=TRUE),
Concentric.Maximum.RFD..N.s.= mean(Concentric.Maximum.RFD..N.s., na.rm=TRUE),
Concentric.Maximum.RFD..Right...N.s.= mean(Concentric.Maximum.RFD..Right...N.s.,na.rm=TRUE),
Concentric.Maximum.RFD..Left...N.s.= mean(Concentric.Maximum.RFD..Left...N.s.,na.rm=TRUE),
Concentric.Impulse..Ns.= mean(Concentric.Impulse..Ns.,na.rm=TRUE),
Concentric.Impulse..Left...Ns.= mean(Concentric.Impulse..Left...Ns.,na.rm=TRUE),
Concentric.Impulse..Right...Ns.= mean(Concentric.Impulse..Right...Ns.,na.rm=TRUE),
Max.Concentric.Peak.Force..N.= mean(Max.Concentric.Peak.Force..N.,na.rm=TRUE),
Max.Eccentric.Peak.Force..N.= mean(Max.Eccentric.Peak.Force..N.,na.rm=TRUE),
Position= get_mode(Position),
.groups = 'drop'
) #60 obs 25 vars
#4 TEST TYPE- IMTP
#DSI
#ballistic, explosive, concurrent
IMTP_L <- Forcedecks_L %>%
filter(Test.Type=="IMTP") %>% #100 obs
select("anon_id", "Date", "Baseline.Force..N.","Baseline.Force..Asym...N.", "Peak.Vertical.Force..N.", "Peak.Vertical.Force...BM..N.kg.", "Peak.Vertical.Force..Asym...N.", "RFD...50ms..N.s.", "RFD...50ms..Asym...N.s.", "RFD...100ms..N.s.", "RFD...100ms..Asym...N.s.", "RFD...150ms..N.s.", "RFD...150ms..Asym...N.s.", "RFD...200ms..N.s.", "RFD...200ms..Asym...N.s.", "Net.Peak.Vertical.Force..N.s.", "Net.Peak.Vertical.Force..Asym...N.s.", "Force.at.200ms...BM..N.kg.", "Eccentric.Asymmetry", "Concentric.Asymmetry","MEAN.Eccentric.Mean.Force.Left", "MEAN.Eccentric.Mean.Force.Right", "MEAN.Concentric.Mean.Force.Left", "MEAN.Concentric.Mean.Force.Right", "MEAN.Concentric.Mean.Force.Asym", "MEAN.Peak.Landing.Force.Asym", "MEAN.Relative.Peak.Power", "MEAN.CMJ.Concentric.Force", "MEAN.Peak.Landing.Force.Left", "MEAN.Peak.Landing.Force.Right", "DSI", "DSI.Bucket") %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y')) %>%
na.omit() %>%
mutate(Sport = 'Basketball') #33 obs & 30 vars
#Forcedecks (VALD) Volleyball Data
#1: TEST TYPE=CMJ
CMJ_V <- Forcedecks_V %>%
filter(Test.Type=="CMJ")
CMJ_V <- subset(CMJ_V, select = c("anon_id","Date","Position","Test.Type","Weight..kg.","Countermovement.Depth..cm.","Peak.Power...BM..W.kg.","Landing.RFD..N.s.", "Eccentric.Concentric.Mean.Force.Ratio", "Peak.Landing.Force..Asym...N.", "Peak.Power..W.","Concentric.Maximum.RFD..N.s.","Concentric.Maximum.RFD..Right...N.s.","Concentric.Maximum.RFD..Left...N.s.","Eccentric.Mean.Braking.Force..N.", "Max.Jump.Height..cm.", "Max.Concentric.Peak.Force..N.", "Relative.Concentric.Power.Bilateral",
"Relative.Eccentric.Power.Bilateral","Max.Peak.Power...BM", "Max.Eccentric.Peak.Force..N.",
"Max.RSI.Modified.VALD","Max.Concentric.RPD..N.s.", "Max.Concentric.Peak.Velocity..m.s.", "Max.Eccentric.Peak.Velocity..m.s.", "Max.Peak.Landing.Force..N.", "MAX.Concentric.Peak.Power..W.","Max.CMJ.Jump.Height..cm.",
"Max.CMJ.RSI.Modified..m.s.","Max.CMJ.Concentric.RPD..N.s.","Max.CMJ.Peak.Power..W.","Max.CMJ.Peak.Landing.Force..N.","CMJ.Concentric.Relative.Peak.Power...Difference.from.First","CMJ.Eccentric.Relative.Peak.Power...Difference.from.First","Eccentric.Asymmetry","Concentric.Asymmetry"
)) #5332 obs & 36 vars
#possible different final dataset
cmj_v <- CMJ_V %>%
na.omit() #457 obs
CMJ_V[CMJ_V==""] <- NA
#combining values from different observations into one
CMJ_v <- CMJ_V %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y')) %>%
filter(Test.Type=="CMJ") %>% #add to others even tho might not need
group_by(anon_id, Date) %>%
summarise(Weight..kg. = mean(Weight..kg., na.rm = TRUE),
Countermovement.Depth..cm.= mean(Countermovement.Depth..cm., na.rm=TRUE),
Peak.Power...BM..W.kg.= mean(Peak.Power...BM..W.kg., na.rm=TRUE),
Landing.RFD..N.s.= mean(Landing.RFD..N.s.,na.rm=TRUE),
Eccentric.Concentric.Mean.Force.Ratio= mean(Eccentric.Concentric.Mean.Force.Ratio,na.rm=TRUE),
Peak.Landing.Force..Asym...N.= mean(Peak.Landing.Force..Asym...N.,na.rm=TRUE),
Peak.Power..W.= mean(Peak.Power..W.,na.rm=TRUE),
Concentric.Maximum.RFD..N.s.= mean(Concentric.Maximum.RFD..N.s.,na.rm=TRUE),
Concentric.Maximum.RFD..Right...N.s.= mean(Concentric.Maximum.RFD..Right...N.s.,na.rm=TRUE),
Concentric.Maximum.RFD..Left...N.s.= mean(Concentric.Maximum.RFD..Left...N.s.,na.rm=TRUE),
Eccentric.Mean.Braking.Force..N.= mean(Eccentric.Mean.Braking.Force..N.,na.rm=TRUE),
Max.Jump.Height..cm.= mean(Max.Jump.Height..cm.,na.rm=TRUE),
Max.Concentric.Peak.Force..N.= mean(Max.Concentric.Peak.Force..N.,na.rm=TRUE),
Relative.Concentric.Power.Bilateral= mean(Relative.Concentric.Power.Bilateral,na.rm=TRUE),
Relative.Eccentric.Power.Bilateral= mean(Relative.Eccentric.Power.Bilateral,na.rm=TRUE),
Max.Peak.Power...BM= mean(Max.Peak.Power...BM,na.rm=TRUE),
Max.Eccentric.Peak.Force..N.= mean(Max.Eccentric.Peak.Force..N.,na.rm=TRUE),
Max.RSI.Modified.VALD= mean(Max.RSI.Modified.VALD,na.rm=TRUE),
Max.Concentric.RPD..N.s.= mean(Max.Concentric.RPD..N.s.,na.rm=TRUE),
Max.Concentric.Peak.Velocity..m.s.= mean(Max.Concentric.Peak.Velocity..m.s.,na.rm=TRUE),
Max.Eccentric.Peak.Velocity..m.s.= mean(Max.Eccentric.Peak.Velocity..m.s.,na.rm=TRUE),
Max.Peak.Landing.Force..N.= mean(Max.Peak.Landing.Force..N.,na.rm=TRUE),
MAX.Concentric.Peak.Power..W.= mean(MAX.Concentric.Peak.Power..W.,na.rm=TRUE),
Max.CMJ.Jump.Height..cm.= mean(Max.CMJ.Jump.Height..cm.,na.rm=TRUE),
Max.CMJ.RSI.Modified..m.s.= mean(Max.CMJ.RSI.Modified..m.s.,na.rm=TRUE),
Max.CMJ.Concentric.RPD..N.s.= mean(Max.CMJ.Concentric.RPD..N.s.,na.rm=TRUE),
Max.CMJ.Peak.Power..W.= mean(Max.CMJ.Peak.Power..W.,na.rm=TRUE),
Max.CMJ.Peak.Landing.Force..N.= mean(Max.CMJ.Peak.Landing.Force..N.,na.rm=TRUE),
CMJ.Concentric.Relative.Peak.Power...Difference.from.First= mean(CMJ.Concentric.Relative.Peak.Power...Difference.from.First,na.rm=TRUE),
CMJ.Eccentric.Relative.Peak.Power...Difference.from.First= mean(CMJ.Eccentric.Relative.Peak.Power...Difference.from.First,na.rm=TRUE),
Position= get_mode(Position),
Eccentric.Asymmetry= get_mode(Eccentric.Asymmetry),
Concentric.Asymmetry= get_mode(Concentric.Asymmetry),
.groups = 'drop'
) # 1416 obs & 32 vars -> 1801 obs w/ Position Eccentric + Concentric Asymmetry
CMJ_vb <- CMJ_v %>%
na.omit() #508 obs & 32 vars -> 173 obs w/ Position Eccentric + Concentric Asymmetry
#selects counter movement jumps another way with normative information
v <- Forcedecks_V %>%
filter(Test.Type == 'CMJ') %>%
dplyr::select("anon_id","Date","Position","Test.Type","Countermovement.Depth..cm.","Peak.Power...BM..W.kg.","Landing.RFD..N.s.", "Eccentric.Concentric.Mean.Force.Ratio", "Peak.Landing.Force..Asym...N.", "Peak.Power..W.", "Concentric.RFD..N.s.", "Concentric.RFD..Left...N.s.","Concentric.RFD..Right...N.s.", "Concentric.Time.to.Peak.Force..s.", "Eccentric.Mean.Braking.Force..N.", "Landing.Net.Peak.Force...BM..N.kg.", "Peak.Net.Takeoff.Force...BM..N.kg.", "Concentric.RPD...BM..W.s.kg.", "Force.at.Peak.Power..N.", "Eccentric.Mean.Deceleration.Force..N.", "Eccentric.Peak.Force..N.", "RSI.Modified..m.s.", "CMJ.Stiffness..Left...N.m.", "CMJ.Stiffness..Right...N.m.", "Eccentric.Asymmetry","Concentric.Asymmetry", "Peak.Landing.Asymmetry", "DSI", "DSI.Bucket", "Eccentric.Peak.Power...BM..W.kg.", "Jump.Height..Imp.Mom...cm.", "Eccentric.Duration..s.", "Eccentric.Deceleration.Impulse..Ns.") %>%
na.omit()
#calculates differences from norm and makes Date a date object
v <- v %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y'),
RSI.Modified..m.s. = RSI.Modified..m.s. / 100,
RSI.Modified.Diff.Norm = (RSI.Modified..m.s. - 0.421) / 0.421,
Ecc.Peak.Power.Rel.Diff.Norm = (Eccentric.Peak.Power...BM..W.kg. - 18) / 18,
Jump.Heigh.Diff.Norm = (Jump.Height..Imp.Mom...cm. - 33) / 33,
Ecc.Duration.Diff.Norm = (Eccentric.Duration..s. - 0.52) / 0.52,
Ecc.Deceleration.Impulse.Diff.Norm = (Eccentric.Deceleration.Impulse..Ns. - 96.0) / 96.0,
Sport = 'Volleyball'
)
#2:TEST TYPE= IMTP
IMTP_V <- Forcedecks_V %>%
filter(Test.Type=="IMTP") %>% #1241
select("anon_id", "Date", "Baseline.Force..N.","Baseline.Force..Asym...N.", "Peak.Vertical.Force..N.", "Peak.Vertical.Force...BM..N.kg.", "Peak.Vertical.Force..Asym...N.", "RFD...50ms..N.s.", "RFD...50ms..Asym...N.s.", "RFD...100ms..N.s.", "RFD...100ms..Asym...N.s.", "RFD...150ms..N.s.", "RFD...150ms..Asym...N.s.", "RFD...200ms..N.s.", "RFD...200ms..Asym...N.s.", "Net.Peak.Vertical.Force..N.s.", "Net.Peak.Vertical.Force..Asym...N.s.", "Force.at.200ms...BM..N.kg.", "Eccentric.Asymmetry", "Concentric.Asymmetry","MEAN.Eccentric.Mean.Force.Left", "MEAN.Eccentric.Mean.Force.Right", "MEAN.Concentric.Mean.Force.Left", "MEAN.Concentric.Mean.Force.Right", "MEAN.Concentric.Mean.Force.Asym", "MEAN.Peak.Landing.Force.Asym", "MEAN.Relative.Peak.Power", "MEAN.CMJ.Concentric.Force", "MEAN.Peak.Landing.Force.Left", "MEAN.Peak.Landing.Force.Right", "DSI", "DSI.Bucket") %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y')) %>%
na.omit() %>%
mutate(Sport = 'Basketball') #249 obs & 30 vars
#3: TEST TYPE= HJ
HJ_V <- Forcedecks_V %>%
filter(Test.Type=="HJ") %>% #367 obs
dplyr::select("anon_id", "Date", "Corrected.Standing.Weight..Kg.", "Mean.RSI..Flight.Contact.Time.", "Active.Stiffness..N.m.", "Best.Average.Force..N.", "Best.Average.Force..Asym...N.", "Best.Time.to.Peak.Force..ms.", "Best.Contact.Time..ms.", "Best.Flight.Time..ms.", "Best.Impulse..N.s.", "Best.Peak.Force..N.", "Best.Peak.Force..Asym...N.", "Mean.Average.Force..N.", "Mean.Average.Force..Asym...N.", "Mean.Landing.RFD..N.s.", "Mean.Landing.RFD..Asym...N.s.", "Stiffness.Fatigue....", "Stiffness.Fatigue..Asym.....", "Max.Jump.Height..cm.", "HJ.RSI", "Mean.Flight.Time..ms.", "Mean.Contact.Time..ms.") %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y')) %>%
na.omit() %>%
mutate(Sport = 'Basketball')
#352 obs & 20 vars
- Performance datasets Of all performance datasets, only basketball
and volleyball have positional norm information but are also missing a
lot of positional information which makes this column sparse. None of
the datasets contain rotational data or razor data. Contain small
amounts of iso prone data.
#Performance (VALD) Basketball Data
#selects variables of interest, nordic and hip data, and cleans up position variable
performance_B <- subset(Performance_B, select = c('anon_id', 'Date', 'Athlete.Bodyweight..kg.','Sport.Position', 'Side', 'Repetitions', 'Maximum.Force', 'Average.Force', 'Impulse', 'Nordic.Left.MEAN', 'Nordic.Right.MEAN', 'Nordic.MEAN.Imbalance', 'Nordic.Left.MAX', 'Nordic.Right.MAX', 'Nordic.MAX.Imbalance', 'Trend', 'Nordic...Difference.from.First.Test', 'Maximum.Nordic.Bilateral.Mean', 'Relative.Maximum.Nordic.Bilateral.Mean', 'Hip.Abd.Left.MEAN', 'Hip.Abd.Right.MEAN', 'Hip.Abduction.MEAN.Imbalance', 'Hip.Abd.Left.MAX', 'Hip.Abd.Right.MAX', 'Hip.Abduction.MAX.Imbalance', 'Hip.Add.Left.MEAN', 'Hip.Add.Right.MEAN', 'Hip.Adduction.MEAN.Imbalance', 'Hip.Add.Left.MAX', 'Hip.Add.Right.MAX', 'Hip.Adduction.MAX.Imbalance', 'Bilateral.Hip.Abduction.Adduction.Ratio')) %>%
mutate(Position = case_when(
Sport.Position == '' ~ 'None',
Sport.Position == '|Guard' ~ 'Guard',
str_detect(Sport.Position, "Primary:") ~ 'Forward',
TRUE ~ Sport.Position
)) %>%
dplyr::select(-Sport.Position)
#makes the date column a 'date' object for later and omits NA values for nordic dataset
performance_B_nordic <- performance_B %>%
dplyr::select(-c('Hip.Abd.Left.MEAN', 'Hip.Abd.Right.MEAN', 'Hip.Abduction.MEAN.Imbalance', 'Hip.Abd.Left.MAX', 'Hip.Abd.Right.MAX', 'Hip.Abduction.MAX.Imbalance', 'Hip.Add.Left.MEAN', 'Hip.Add.Right.MEAN', 'Hip.Adduction.MEAN.Imbalance', 'Hip.Add.Left.MAX', 'Hip.Add.Right.MAX', 'Hip.Adduction.MAX.Imbalance', 'Bilateral.Hip.Abduction.Adduction.Ratio')) %>%
filter(Athlete.Bodyweight..kg. > 5) %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y'),
Force.Diff.Norm = (Maximum.Nordic.Bilateral.Mean - 308) / 308,
Imbalance.Diff.Norm = (Nordic.MEAN.Imbalance - 6.3) / 6.3,
Sport = 'Basketball') %>%
na.omit()
#makes the date column a 'date' object for later and omits NA values for hip dataset
performance_B_hip <- performance_B %>%
dplyr::select(-c('Nordic.Left.MEAN', 'Nordic.Right.MEAN', 'Nordic.MEAN.Imbalance', 'Nordic.Left.MAX', 'Nordic.Right.MAX', 'Nordic.MAX.Imbalance', 'Trend', 'Nordic...Difference.from.First.Test', 'Maximum.Nordic.Bilateral.Mean', 'Relative.Maximum.Nordic.Bilateral.Mean')) %>%
filter(Athlete.Bodyweight..kg. > 5) %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y'),
Abd.Add.Ratio.Diff.Norm = (Bilateral.Hip.Abduction.Adduction.Ratio - 1) / 1,
Sport = 'Basketball') %>%
na.omit()
Need to either get more data on positions of players or get rid of
percent difference from norm since it has a lot of NAs. Could consider
athlete bodyweight as well to put strength relatively but also has
missing data and has negative values? Also missing a decent amount of
z-score observations. 147 observations with percent difference norm and
z-scores. 550 with only z-scores. 592 with neither percent difference
norm or z-scores. If we include athlete bodyweight and exclude percent
difference norm and z-scores there are 521 observations.
Hip dataset contains 109 observations including the bodyweight
variable, 129 otherwise.
#Performance (VALD) Soccer Data
#selects variables of interest, nordic and hip data, and cleans up position variable
performance_S <- subset(Performance_S, select = c('anon_id', 'Date', 'Athlete.Bodyweight..kg.','Sport.Position', 'Side', 'Repetitions', 'Maximum.Force', 'Average.Force', 'Impulse', 'Nordic.Left.MEAN', 'Nordic.Right.MEAN', 'Nordic.MEAN.Imbalance', 'Nordic.Left.MAX', 'Nordic.Right.MAX', 'Nordic.MAX.Imbalance', 'Trend', 'Nordic...Difference.from.First.Test', 'Maximum.Nordic.Bilateral.Mean', 'Relative.Maximum.Nordic.Bilateral.Mean', 'Hip.Abd.Left.MEAN', 'Hip.Abd.Right.MEAN', 'Hip.Abduction.MEAN.Imbalance', 'Hip.Abd.Left.MAX', 'Hip.Abd.Right.MAX', 'Hip.Abduction.MAX.Imbalance', 'Hip.Add.Left.MEAN', 'Hip.Add.Right.MEAN', 'Hip.Adduction.MEAN.Imbalance', 'Hip.Add.Left.MAX', 'Hip.Add.Right.MAX', 'Hip.Adduction.MAX.Imbalance', 'Bilateral.Hip.Abduction.Adduction.Ratio')) %>%
mutate(Position = case_when(
Sport.Position == '' ~ 'None',
TRUE ~ Sport.Position
)) %>%
dplyr::select(-Sport.Position)
#makes the date column a 'date' object for later and omits NA values for nordic dataset
performance_S_nordic <- performance_S %>%
dplyr::select(-c('Hip.Abd.Left.MEAN', 'Hip.Abd.Right.MEAN', 'Hip.Abduction.MEAN.Imbalance', 'Hip.Abd.Left.MAX', 'Hip.Abd.Right.MAX', 'Hip.Abduction.MAX.Imbalance', 'Hip.Add.Left.MEAN', 'Hip.Add.Right.MEAN', 'Hip.Adduction.MEAN.Imbalance', 'Hip.Add.Left.MAX', 'Hip.Add.Right.MAX', 'Hip.Adduction.MAX.Imbalance', 'Bilateral.Hip.Abduction.Adduction.Ratio')) %>%
filter(Athlete.Bodyweight..kg. > 5) %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y'),
Force.Diff.Norm = (Maximum.Nordic.Bilateral.Mean - 298) / 298,
Imbalance.Diff.Norm = (Nordic.MEAN.Imbalance - 6.5) / 6.5,
Sport = 'Soccer') %>%
na.omit()
#makes the date column a 'date' object for later and omits NA values for hip dataset
performance_S_hip <- performance_S %>%
dplyr::select(-c('Nordic.Left.MEAN', 'Nordic.Right.MEAN', 'Nordic.MEAN.Imbalance', 'Nordic.Left.MAX', 'Nordic.Right.MAX', 'Nordic.MAX.Imbalance', 'Trend', 'Nordic...Difference.from.First.Test', 'Maximum.Nordic.Bilateral.Mean', 'Relative.Maximum.Nordic.Bilateral.Mean')) %>%
filter(Athlete.Bodyweight..kg. > 5) %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y'),
Abd.Add.Ratio.Diff.Norm = (Bilateral.Hip.Abduction.Adduction.Ratio - 0.98) / 0.98,
Sport = 'Soccer') %>%
na.omit()
Does not contain any information about positional norms so there are
no percent differences from norm. 421 observations with z-scores. 483
observations without z-scores. There are 400 observations if bodyweight
is included.
Hip dataset contains only 39 observations with body weight included
and without it included.
#Performance (VALD) Lacrosse Data
#selects variables of interest, nordic and hip data, and cleans up position variable
performance_L <- subset(Performance_L, select = c('anon_id', 'Date', 'Athlete.Bodyweight..kg.','Sport.Position', 'Side', 'Repetitions', 'Maximum.Force', 'Average.Force', 'Impulse', 'Nordic.Left.MEAN', 'Nordic.Right.MEAN', 'Nordic.MEAN.Imbalance', 'Nordic.Left.MAX', 'Nordic.Right.MAX', 'Nordic.MAX.Imbalance', 'Trend', 'Nordic...Difference.from.First.Test', 'Maximum.Nordic.Bilateral.Mean', 'Relative.Maximum.Nordic.Bilateral.Mean', 'Hip.Abd.Left.MEAN', 'Hip.Abd.Right.MEAN', 'Hip.Abduction.MEAN.Imbalance', 'Hip.Abd.Left.MAX', 'Hip.Abd.Right.MAX', 'Hip.Abduction.MAX.Imbalance', 'Hip.Add.Left.MEAN', 'Hip.Add.Right.MEAN', 'Hip.Adduction.MEAN.Imbalance', 'Hip.Add.Left.MAX', 'Hip.Add.Right.MAX', 'Hip.Adduction.MAX.Imbalance', 'Bilateral.Hip.Abduction.Adduction.Ratio')) %>%
mutate(Position = case_when(
Sport.Position == '' ~ 'None',
TRUE ~ Sport.Position
)) %>%
dplyr::select(-Sport.Position)
#makes the date column a 'date' object for later and omits NA values for nordic dataset
performance_L_nordic <- performance_L %>%
dplyr::select(-c('Hip.Abd.Left.MEAN', 'Hip.Abd.Right.MEAN', 'Hip.Abduction.MEAN.Imbalance', 'Hip.Abd.Left.MAX', 'Hip.Abd.Right.MAX', 'Hip.Abduction.MAX.Imbalance', 'Hip.Add.Left.MEAN', 'Hip.Add.Right.MEAN', 'Hip.Adduction.MEAN.Imbalance', 'Hip.Add.Left.MAX', 'Hip.Add.Right.MAX', 'Hip.Adduction.MAX.Imbalance', 'Bilateral.Hip.Abduction.Adduction.Ratio')) %>%
filter(Athlete.Bodyweight..kg. > 5) %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y'),
Force.Diff.Norm = (Maximum.Nordic.Bilateral.Mean - 277) / 277,
Imbalance.Diff.Norm = (Nordic.MEAN.Imbalance - 5.8) / 5.8,
Sport = 'Lacrosse') %>%
na.omit()
#makes the date column a 'date' object for later and omits NA values for hip dataset
performance_L_hip <- performance_L %>%
dplyr::select(-c('Nordic.Left.MEAN', 'Nordic.Right.MEAN', 'Nordic.MEAN.Imbalance', 'Nordic.Left.MAX', 'Nordic.Right.MAX', 'Nordic.MAX.Imbalance', 'Trend', 'Nordic...Difference.from.First.Test', 'Maximum.Nordic.Bilateral.Mean', 'Relative.Maximum.Nordic.Bilateral.Mean')) %>%
filter(Athlete.Bodyweight..kg. > 5) %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y'),
Abd.Add.Ratio.Diff.Norm = (Bilateral.Hip.Abduction.Adduction.Ratio - 0.99) / 0.99,
Sport = 'Lacrosse') %>%
na.omit()
Also does not contain any information about positional norms so there
are no percent differences from norm. 855 observations with z-scores.
929 observations without z-scores. 810 observations if bodyweight is
included.
Hip dataset contains 100 observations with bodyweight included and
excluded.
#Performance (VALD) Volleyball Data
#selects variables of interest, nordic and hip data
performance_V <- subset(Performance_V, select = c('anon_id', 'Date', 'Athlete.Bodyweight..kg.','Sport.Position', 'Side', 'Repetitions', 'Maximum.Force', 'Average.Force', 'Impulse', 'Nordic.Left.MEAN', 'Nordic.Right.MEAN', 'Nordic.MEAN.Imbalance', 'Nordic.Left.MAX', 'Nordic.Right.MAX', 'Nordic.MAX.Imbalance', 'Trend', 'Nordic...Difference.from.First.Test', 'Maximum.Nordic.Bilateral.Mean', 'Relative.Maximum.Nordic.Bilateral.Mean', 'Hip.Abd.Left.MEAN', 'Hip.Abd.Right.MEAN', 'Hip.Abduction.MEAN.Imbalance', 'Hip.Abd.Left.MAX', 'Hip.Abd.Right.MAX', 'Hip.Abduction.MAX.Imbalance', 'Hip.Add.Left.MEAN', 'Hip.Add.Right.MEAN', 'Hip.Adduction.MEAN.Imbalance', 'Hip.Add.Left.MAX', 'Hip.Add.Right.MAX', 'Hip.Adduction.MAX.Imbalance', 'Bilateral.Hip.Abduction.Adduction.Ratio')) %>%
mutate(Position = case_when(
Sport.Position == '' ~ 'None',
TRUE ~ Sport.Position
)) %>%
dplyr::select(-Sport.Position)
#makes the date column a 'date' object for later and omits NA values for nordic dataset
performance_V_nordic <- performance_V %>%
dplyr::select(-c('Hip.Abd.Left.MEAN', 'Hip.Abd.Right.MEAN', 'Hip.Abduction.MEAN.Imbalance', 'Hip.Abd.Left.MAX', 'Hip.Abd.Right.MAX', 'Hip.Abduction.MAX.Imbalance', 'Hip.Add.Left.MEAN', 'Hip.Add.Right.MEAN', 'Hip.Adduction.MEAN.Imbalance', 'Hip.Add.Left.MAX', 'Hip.Add.Right.MAX', 'Hip.Adduction.MAX.Imbalance', 'Bilateral.Hip.Abduction.Adduction.Ratio')) %>%
filter(Athlete.Bodyweight..kg. > 5) %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y'),
Force.Diff.Norm = (Maximum.Nordic.Bilateral.Mean - 287) / 287,
Imbalance.Diff.Norm = (Nordic.MEAN.Imbalance - 6.2) / 6.2,
Sport = 'Volleyball') %>%
na.omit()
#makes the date column a 'date' object for later and omits NA values for hip dataset
performance_V_hip <- performance_V %>%
dplyr::select(-c('Nordic.Left.MEAN', 'Nordic.Right.MEAN', 'Nordic.MEAN.Imbalance', 'Nordic.Left.MAX', 'Nordic.Right.MAX', 'Nordic.MAX.Imbalance', 'Trend', 'Nordic...Difference.from.First.Test', 'Maximum.Nordic.Bilateral.Mean', 'Relative.Maximum.Nordic.Bilateral.Mean')) %>%
filter(Athlete.Bodyweight..kg. > 5) %>%
mutate(Date = as.Date(Date, format = '%m/%d/%Y'),
Abd.Add.Ratio.Diff.Norm = (Bilateral.Hip.Abduction.Adduction.Ratio - 1.04) / 1.04,
Sport = 'Volleyball') %>%
na.omit()
There are a lot of observations with the player playing multiple
positions, need to figure out how to filter down when analyzing data by
positions.
Does have positional norm information but a lot of missing values.
Only 33 observations with percent difference norm and z-scores. 356
observations with only z-scores. 393 observations without either percent
difference norm or z-scores. 325 observations if bodyweight is
included.
Hip data contains 180 observations with bodyweight included, 220
otherwise.
Exploratory Plots
- Incident datasets
#density plot of injuries across the different parts of a season
ggplot(incident_b, aes(x=Season.))+
geom_bar(fill="#CFB87C")+
labs(title="Seasonal Injury Spread",x="Season",y="Frequency")

ggplot(incident_b, aes(x=General.mechanism))+
geom_bar(fill="#CFB87C")+
labs(title="Seasonal Injury Spread by Mechanism",x="Mechanism",y="Frequency")

ggplot(incident_b, aes(x=Position))+
geom_bar(fill="#CFB87C")+
labs(title="Positional Injury Spread",x="Players Positions",y="Frequency")

Contact injuries seem to be the biggest concern for womens basketball
are focus of lower body injuries is typically non-contact. In-season is
the biggest time for injuries in basketball.
#density plot of injuries across the different parts of a season
ggplot(incident_s, aes(x=Season.))+
geom_bar(fill="#CFB87C")+
labs(title="Seasonal Injury Spread",x="Season",y="Frequency")

ggplot(incident_s, aes(x=General.mechanism))+
geom_bar(fill="#CFB87C")+
labs(title="Seasonal Injury Spread by Mechanism",x="Mechanism",y="Frequency")

ggplot(incident_s, aes(x=Position))+
geom_bar(fill="#CFB87C")+
labs(title="Positional Injury Spread",x="Players Positions",y="Frequency")

Highest frequency of lower body injuries in-season but an
unexpectedly high rate of lower body injuries in the off season as well.
Contact injuries are 2x as likely as a non-contact injury.
#density plot of injuries across the different parts of a season
ggplot(incident_v, aes(x=Season.))+
geom_bar(fill="#CFB87C")+
labs(title="Seasonal Injury Spread",x="Season",y="Frequency")

ggplot(incident_v, aes(x=General.mechanism))+
geom_bar(fill="#CFB87C")+
labs(title="Seasonal Injury Spread by Mechanism",x="Injury Mechanism",y="Frequency")

ggplot(incident_v, aes(x=Position))+
geom_bar(fill="#CFB87C")+
theme(axis.text.x=element_text(angle=45,hjust=1))+
labs(title="Positional Injury Spread",x="Players Positions",y="Frequency")

This is the first sport that we see the highest lower body injury
frequency as non-contact injury mechanism, higher probability of greater
lower body injuries in volleyball then basketball and soccer.
#density plot of injuries across the different parts of a season
ggplot(incident_l, aes(x=Season.))+
geom_bar(fill="#CFB87C")+
labs(title="Seasonal Injury Spread",x="Season",y="Frequency")

ggplot(incident_l, aes(x=General.mechanism))+
geom_bar(fill="#CFB87C")+
labs(title="Seasonal Injury Spread by Mechanism",x="Mechanism",y="Frequency")

ggplot(incident_l, aes(x=Position))+
geom_bar(fill="#CFB87C")+
labs(title="Positional Injury Spread",x="Players Positions",y="Frequency")

Like volleyball strong lead of non-contact injuries then any other
type of injury mechanism.
- Dynamo datasets
#adding a column to each dataset describing the sport for exploratory purposes
dynamo_B$Sport <- 'Basketball'
dynamo_S$Sport <- 'Soccer'
dynamo_L$Sport <- 'Lacrosse'
dynamo_V$Sport <- 'Volleyball'
#creating a dataset containing dynamo data accross all sports
dynamo_all <- rbind(dynamo_B, dynamo_S, dynamo_L, dynamo_V) %>%
mutate(Avg.Max.Force = (Knee.Ex.Right.Side.Max.Force..N. + Knee.Ex.Left.Side.Max.Force..N.) / 2)
#creates a boxplot of average force asymmetry across the 4 sports
ggplot(dynamo_all, aes(x = Knee.Ex.Avg.Force.Asymmetry, y = Sport)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of Avgerage Force Asymmetry Across Sports',
y = 'Sport',
x = 'Average Force Asymmetry') +
theme_bw()

#creates a histogram of dynamo max force across the 4 sports
ggplot(dynamo_all, aes(x = Avg.Max.Force, fill = Sport)) +
geom_histogram(color = 'black', position = 'identity', bins = 20) +
scale_fill_manual(values = c('#565A5C', '#CFB87C', '#000000', '#A2A4A3')) +
labs(title = 'Distribution of Average Dynamo Max Force Across Sports',
y = 'Sport',
x = 'Average Max Force (N)') +
theme_bw()

This data will probably not be very useful especially since only two
unique players are represented in WBB, and only one in both WVB and WSOC
WLAX has 9 unique players but very few comparisons can be made across
sports.
- Forcedecks Variable Distribution Plots
#basketball, CMJ test: distribution of max RSI
ggplot(CMJ_bb, aes(Max.CMJ.RSI.Modified..m.s.)) +
labs(title="Distribution of Maximum RSI in CMJ Test",x="RSI", y="Frequency") +
geom_histogram(fill="#CFB87C")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

#HJ TEST: distribution of Mean.RSI..Flight.Contact.Time
ggplot(HJ_B, aes(Mean.RSI..Flight.Contact.Time.)) +
labs(title="Distribution of RSI Flight Contact Time in the Hop Jump Test",x="Average RSI Flight Contact Time", y="Frequency") +
geom_histogram(fill="#CFB87C")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

#IMTP test: distribution of peak vert. force
ggplot(IMTP_B, aes(Net.Peak.Vertical.Force..N.s.)) +
labs(title="Distribution of IMTP Test",x="Peak Vertical Force", y="Frequency") +
geom_histogram(fill="#CFB87C")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

#SOCCER, CMJ test: distribution of max RSI
ggplot(CMJ_soc, aes(Max.CMJ.RSI.Modified..m.s.)) +
labs(title="Distribution of Maximum RSI in CMJ Test",x="RSI", y="Frequency") +
geom_histogram(fill="#CFB87C")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

#HJ TEST: distribution of Mean.RSI..Flight.Contact.Time
ggplot(HJ_S, aes(Mean.RSI..Flight.Contact.Time.)) +
labs(title="Distribution of RSI Flight Contact Time in the Hop Jump Test",x="Average RSI Flight Contact Time", y="Frequency") +
geom_histogram(fill="#CFB87C")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

#IMTP test: distribution of peak vert. force
ggplot(IMTP_S, aes(Net.Peak.Vertical.Force..N.s.)) +
labs(title="Distribution of IMTP Test",x="Peak Vertical Force", y="Frequency") +
geom_histogram(fill="#CFB87C")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

#SLJ test: distribution
ggplot(SLJ_S, aes(Concentric.Impulse..Ns.)) +
labs(title="Distribution of Concentric Impulse in SLJ Test",x="Concentric Impulse", y="Frequency") +
geom_histogram(fill="#CFB87C")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

#LACROSSE, CMJ test: distribution of max RSI
ggplot(CMJ_lax, aes(Max.CMJ.RSI.Modified..m.s.)) +
labs(title="Distribution of Maximum RSI in CMJ Test",x="RSI", y="Frequency") +
geom_histogram(fill="#CFB87C")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

#HJ TEST: distribution of Mean.RSI..Flight.Contact.Time
ggplot(HJ_L, aes(Mean.RSI..Flight.Contact.Time.)) +
labs(title="Distribution of RSI Flight Contact Time in the Hop Jump Test",x="Average RSI Flight Contact Time", y="Frequency") +
geom_histogram(fill="#CFB87C")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

#IMTP test: distribution of peak vert. force
ggplot(IMTP_L, aes(Net.Peak.Vertical.Force..N.s.)) +
labs(title="Distribution of IMTP Test",x="Peak Vertical Force", y="Frequency") +
geom_histogram(fill="#CFB87C")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

#SLJ test: distribution
ggplot(SLJ_L, aes(Concentric.Impulse..Ns.)) +
labs(title="Distribution of Concentric Impulse in SLJ Test",x="Concentric Impulse", y="Frequency") +
geom_histogram(fill="#CFB87C")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

#VOLLEYBALL, CMJ test: distribution of max RSI
ggplot(CMJ_vb, aes(Max.CMJ.RSI.Modified..m.s.)) +
labs(title="Distribution of Maximum RSI in CMJ Test",x="RSI", y="Frequency") +
geom_histogram(fill="#CFB87C")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

#HJ TEST: distribution of Mean.RSI..Flight.Contact.Time
ggplot(HJ_V, aes(Mean.RSI..Flight.Contact.Time.)) +
labs(title="Distribution of RSI Flight Contact Time in the Hop Jump Test",x="Average RSI Flight Contact Time", y="Frequency") +
geom_histogram(fill="#CFB87C")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

#IMTP test: distribution of peak vert. force
ggplot(IMTP_V, aes(Net.Peak.Vertical.Force..N.s.)) +
labs(title="Distribution of IMTP Test",x="Peak Vertical Force", y="Frequency") +
geom_histogram(fill="#CFB87C")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

- Performance
#BASKETBALL
#summarizes the number of unique athletes per position group
performance_B_nordic %>%
group_by(Position) %>%
summarize(`Unique Athletes` = n_distinct(anon_id))
There are only 4 unique centers represented with most of the
observations being ID_40 and ID_51, ID_15 and ID_30 each only have one
observation. Forwards only have 8 unique players but the split between
these players is more even with the exception of ID_24 who only has one
observation. Guards has 10 unique players with ID_55 making up a large
proportion of these observations and ID_5, ID_54, and ID_63 only being
represented once.
#creates a boxplot of maximum relative bilateral force across the basketball positions
ggplot(performance_B_nordic, aes(x = Relative.Maximum.Nordic.Bilateral.Mean, y = Position)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of Maximum Relative Bilateral Force Across Basketball Postions',
y = 'Position',
x = 'Maximum Relative Bilateral Force (N / kg)') +
theme_bw()

Centers appear to have a far greater variability in force along with
a lower median of force in comparison to forwards and guards. The same
appears to be true for the relative force. Interestingly when plotting
the athlete bodyweight vs position there is no signifiant differences
and the median weight for centers is less than the median weight of
guards and forwards.
#SOCCER
#summarizes the number of unique athletes per position group
performance_S_nordic %>%
group_by(Position) %>%
summarize(`Unique Athletes` = n_distinct(anon_id))
There are only one unique outside back and center back players. Only
4 defense midfield players with ID_32 only having one observation. Only
3 goalies, relatively even distribution of observations. 7 forwards,
also pretty even distribution of observations. 7 midfeilders with ID_94
and ID_32 only representing one observation each.
#creates a boxplot of maximum relative bilateral force across the basketball positions
ggplot(performance_S_nordic, aes(x = Relative.Maximum.Nordic.Bilateral.Mean, y = Position)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of Maximum Relative Bilateral Force Across Basketball Postions',
y = 'Position',
x = 'Maximum Relative Bilateral Force (N / kg)') +
theme_bw()

There is a big outlier in ID_3 whos mean maximum bilateral force in
newtons was less than her bodyweight in kg.
#LACROSSE
#summarizes the number of unique athletes per position group
performance_L_nordic %>%
group_by(Position) %>%
summarize(`Unique Athletes` = n_distinct(anon_id))
This dataset seems to have a better amount of unique players per
position.
#creates a boxplot of maximum relative bilateral force across the basketball positions
ggplot(performance_L_nordic, aes(x = Relative.Maximum.Nordic.Bilateral.Mean, y = Position)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of Maximum Relative Bilateral Force Across Basketball Postions',
y = 'Position',
x = 'Maximum Relative Bilateral Force (N / kg)') +
theme_bw()

All the positions seem to have a similar distribution of maximum
relative bilateral force.
#VOLLEYBALL
#summarizes the number of unique athletes per position group
performance_V_nordic %>%
group_by(Position) %>%
summarize(`Unique Athletes` = n_distinct(anon_id))
There are very few unique athletes per position in this dataset, need
to figure out how we can assign two position athletes into one for
better analysis of positions.
#creates a boxplot of maximum relative bilateral force across the basketball positions
ggplot(performance_V_nordic, aes(x = Relative.Maximum.Nordic.Bilateral.Mean, y = Position)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of Maximum Relative Bilateral Force Across Basketball Postions',
y = 'Position',
x = 'Maximum Relative Bilateral Force (N / kg)') +
theme_bw()

##MERGE DATASETS -incident + performance (nordic + hip), forceframe
(multiple tests) -dynamo not to be added These are grouped by all data
of each sport. Do not know if will use as we want to compare metrics
across sports. Keep Just in case.
#basketball incidents + tests
B_incid_CMJtest <- merge(incident_b, CMJ_bb, by=c('anon_id'),all=TRUE) #1312 by 61
B_incid_HJtest <- merge(incident_b, HJ_B, by=c('anon_id'),all=TRUE) #2020 by 46
B_incid_IMTPtest <- merge(incident_b, IMTP_B, by=c('anon_id'),all=TRUE) #315 by 56
#soccer incidents + tests
S_incid_CMJtest <- merge(incident_s, CMJ_soc, by=c('anon_id'),all=TRUE) #1911 by 63
S_incid_HJtest <- merge(incident_s, HJ_S, by=c('anon_id'),all=TRUE) #3200 by 47
S_incid_IMTPtest <- merge(incident_s, IMTP_S, by=c('anon_id'),all=TRUE) #596 by 57
S_incid_SLJtest <- merge(incident_s, SLJ_S, by=c('anon_id'),all=TRUE) #3723 by 52
##RESEARCH QUESTIONS******* #Q1: What are meaningful thresholds for
strength metrics as they relate to lower body injury risk? a. For
example, one of our strength coaches uses 5 times body weight (kg) in
Newtons for hamstring strength as a cutoff for injury risk. Is this
supported by our data?
-looking for meaningful strength metrics to lower body injury risk
-create thresholds for these metrics by each position in each sport
#merge all incident datasets
all_incident <- bind_rows(incident_b, incident_s, incident_v,incident_l) %>%
select(-c(Incident.Type,Total.Time.Injured.1))
#PERFORMANCE
#create a dataset containing all performance hip data across all sports + combine w/ incidents
all_perf_hip <- rbind(performance_B_hip, performance_L_hip, performance_S_hip, performance_V_hip)
all_hip_incident <- merge(all_incident, all_perf_hip,by=c('anon_id'), na.rm=TRUE) #1528 v 49
#create a dataset containing all preformance nordic data across all sports + combine w/ incidents
all_perf_nordic <- rbind(performance_B_nordic, performance_L_nordic, performance_S_nordic, performance_V_nordic)
#GIVEN
#confirm or deny threshold of 5x bodyweight (kg) in N for hamstring strength for injury risk
all_perf_nordic <- all_perf_nordic %>%
mutate(strength_ratio=Maximum.Nordic.Bilateral.Mean/Athlete.Bodyweight..kg.,
above_threshold=ifelse(strength_ratio>= 5, 1,0)) #hamstring strength/weight
all_nordic_incident <- merge(all_incident, all_perf_nordic,by=c('anon_id'), na.rm=TRUE) #6491 v 48
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_nordic_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_nordic_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.46184 0.03683 39.689 < 2e-16 ***
above_threshold -0.26845 0.07700 -3.486 0.00049 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 6007.4 on 6049 degrees of freedom
Residual deviance: 5995.6 on 6048 degrees of freedom
AIC: 5999.6
Number of Fisher Scoring iterations: 4
Above threshold having a negative estimate and being significant ,
means that being above the 5x threshold is associated with a reduction
in injury odds. Therefore being above the threshold does relate to lower
body risk.
#STACKED BAR CHART
injury_counts <- all_nordic_incident %>%
mutate(
Threshold = ifelse(above_threshold == 1, "≥ 5x Athletes Bodyweight", "< 5x Athletes Bodyweight"),
Injury = ifelse(LB.Injury == 1, "Injured", "Not Injured")
) %>%
count(Threshold, Injury)
#Plot
ggplot(injury_counts, aes(x = Threshold, y = n, fill = Injury)) +
geom_bar(stat = "identity", position = "stack") +
scale_fill_manual(values=c("Injured"='#CFB87C',"Not Injured"='#000000'))+
labs(
title = "Lower Body Injury Count by Hamstring Strength Threshold",
x = "Hamstring Strength",
y = "Count",
fill = "Lower Body Injury Status"
) +
theme_minimal()

#proportions GRAPHIC
injury_props <- all_nordic_incident %>%
mutate(
Threshold = ifelse(above_threshold == 1, "≥ 5x Athletes Bodyweight", "< 5x Athletes Bodyweight"),
Injury = ifelse(LB.Injury == 1, "Injured", "Not Injured")
) %>%
count(Threshold, Injury) %>%
group_by(Threshold) %>%
mutate(prop = n / sum(n))
#plot
ggplot(injury_props, aes(x = Threshold, y = prop, fill = Injury)) +
geom_bar(stat = "identity", position = "fill") +
scale_fill_manual(values=c("Injured"='#CFB87C',"Not Injured"='#000000'))+
scale_y_continuous(labels = scales::percent_format()) +
labs(
title = "Proportion of Athletes with a Lower Body Injury vs No Injury by Threshold",
x = "Hamstring Strength",
y = "Proportion",
fill = "Lower BodyI njury Status"
) +
theme_minimal()

Combining forcedecks data with incident data to compare injuries
across all sports with forcedeck strength information.
#make all merging datasets the same # if variables
CMJ_bb <- CMJ_bb %>%
select(-c(Test.Type))
CMJ_soc <- CMJ_soc %>%
select(-c(Test.Type))
CMJ_lax <- CMJ_lax %>%
select(-c(Test.Type))
#create a dataset containing all CMJ test data across all sports
all_CMJ <- rbind(CMJ_bb, CMJ_soc, CMJ_lax, CMJ_vb)
all_CMJ_incident <- merge(all_incident, all_CMJ,by=c('anon_id'), na.rm=TRUE) #3471 v 67
#create a dataset containing all HJ test data across all sports
all_hopjump <- rbind(HJ_B, HJ_S, HJ_L, HJ_V)
all_hopjump_incident <- merge(all_incident, all_hopjump,by=c('anon_id'), na.rm=TRUE) #5597 v 47
#create a dataset containing all IMTP test data across all sports
all_IMTP <- rbind(IMTP_B, IMTP_S, IMTP_L, IMTP_V)
all_IMTP_incident <- merge(all_incident, all_IMTP,by=c('anon_id'), na.rm=TRUE) #1552 v 57
#create a dataset containing all SLJ test data across all sports
all_SLJ <- rbind(SLJ_s, SLJ_l)
all_SLJ_incident <- merge(all_incident, all_SLJ,by=c('anon_id'), na.rm=TRUE) #461 v 52
##FINDING MY OWN THRESHOLDS #Preformance data
#way to find threshold
all_hip_incident$LB.Injury <- as.factor(all_hip_incident$LB.Injury)
cp <- cutpointr(all_hip_incident, Bilateral.Hip.Abduction.Adduction.Ratio, LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 0
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Bilateral.Hip.Abduction.Adduction.Ratio
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.5406 1363 300 1063
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
1.024 0.1346 0.6236 0.4667 0.6679 140 160 353 710
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max. SD NAs
Overall 0.008 0.75600 0.9115 0.9820 1.112831 1.098 1.465 114.668 3.0878479 0
0 0.024 0.82535 0.9180 1.0055 1.045813 1.110 1.465 2.911 0.2572247 0
1 0.008 0.73100 0.9110 0.9740 1.131744 1.077 1.465 114.668 3.4939944 0
For Bilateral hip abduction adduction ratio the optimal cutpoint is
1.024 with a AUC of 0.5482, sensitivity of 0.4873 and specificity of
0.6564.
#other way to find threshold
#ROC object
roc_obj <- roc(response = all_hip_incident$LB.Injury,
predictor = all_hip_incident$Bilateral.Hip.Abduction.Adduction.Ratio, #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Bilateral Hip Abduction Adduction.Ratio")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.5406
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

The Bilateral Hip abduction adduction threshold is 1.0235 with a
sensitivity of 0.6564365 and a specificity of 0.4873239 and an AUC of
0.5482
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_hip_incident <- all_hip_incident %>%
mutate(above_threshold=ifelse(Bilateral.Hip.Abduction.Adduction.Ratio>= 1.024, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_hip_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_hip_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.49009 0.08751 17.027 < 2e-16 ***
above_threshold -0.56527 0.13279 -4.257 2.07e-05 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 1436.7 on 1362 degrees of freedom
Residual deviance: 1418.8 on 1361 degrees of freedom
AIC: 1422.8
Number of Fisher Scoring iterations: 4
odds.ratio=exp(-0.59674)
(1-odds.ratio)*100
[1] 44.93963
#GRAPHICS
#density plot
ggplot(all_hip_incident, aes(x = Bilateral.Hip.Abduction.Adduction.Ratio, fill = LB.Injury)) +
geom_density(alpha = 0.4) +
geom_vline(xintercept = 1.024, linetype = "dashed", color = "red", size = 1) +
labs(title = "Density Plot: Bilateral Hip Abduction-Adduction Ratio by Injury Status",
x = "Bilateral Hip Abduction-Adduction Ratio",
y = "Density") +
scale_fill_manual(values = c("0" = "#000000", "1" = "#CFB87C"),
name = "Lower Body Injury", labels = c("No", "Yes")) +
scale_x_continuous(limits =c(0,3))
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.
This warning is displayed once every 8 hours.
Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.
Warning: Removed 1 row containing non-finite outside the scale range (`stat_density()`).

#boxplot
ggplot(all_hip_incident, aes(x = LB.Injury, y = Bilateral.Hip.Abduction.Adduction.Ratio, fill = LB.Injury)) +
geom_boxplot(alpha = 0.7) +
geom_hline(yintercept = 1.024, linetype = "dashed", color = "red") +
labs(title = "Boxplot: Bilateral Hip Abduction-Adduction Ratio by Injury Status",
x = "Lower Body Injury", y = "Bilateral Hip Abduction-Adduction Ratio") +
scale_fill_manual(values = c("0" = "#000000", "1" ="#CFB87C"),
name = "LB Injury", labels = c("No", "Yes")) +
scale_y_continuous(limits =c(0,3))
Warning: Removed 1 row containing non-finite outside the scale range (`stat_boxplot()`).

#another count distribution
injury_counts <- all_hip_incident %>%
mutate(
Threshold = ifelse(above_threshold == 1, "Above", "Below"),
Injury = ifelse(LB.Injury == 1, "Yes", "No")
) %>%
count(Threshold, Injury)
ggplot(injury_counts, aes(x = Threshold, y = n, fill = Injury)) +
geom_bar(stat = "identity", position = "stack") +
scale_fill_manual(values=c("Yes"='#CFB87C',"No"='#000000'))+
labs(
title = "Lower Body Injury Count Above vs Below the Bilateral Hip Abduction-Adduction Threshold",
x = "Bilateral Hip Abduction-Adduction Ratio Threshold",
y = "Count",
fill = "Lower Body Injury"
) +
theme_minimal()

#proportions distribution
threshold_summary <- all_hip_incident %>%
group_by(above_threshold, LB.Injury) %>%
summarise(count = n()) %>%
mutate(prop = count / sum(count))
`summarise()` has grouped output by 'above_threshold'. You can override using the
`.groups` argument.
ggplot(threshold_summary, aes(x = factor(above_threshold), y = prop, fill = factor(LB.Injury))) +
geom_bar(stat = "identity", position = "fill") +
scale_fill_manual(values = c("0" = "#000000", "1" = "#CFB87C"),
name = "Lower Body Injury", labels = c("No", "Yes")) +
labs(x = "Bilateral Hip Abduction-Adduction Ratio Threshold", y = "Proportion",
title = "Lower Body Injury Proportions Above vs Below the Bilateral Hip Abduction-Adduction Threshold") +
scale_x_discrete(labels = c("0" = "Below", "1" = "Above"))

#variable IMPULSE
all_hip_incident$LB.Injury <- as.factor(all_hip_incident$LB.Injury)
cp <- cutpointr(all_hip_incident, Impulse, LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 1
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Impulse
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.5242 1363 1063 300
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
2699.975 0.0774 0.3346 0.174 0.9033 185 878 29 271
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max. SD
Overall 0 824.4465 1462.965 1843.49 1970.372 2330.220 3383.070 4488.775 762.6786
0 0 992.1293 1461.210 1808.05 1890.834 2309.062 3059.367 3974.770 646.6791
1 0 823.6200 1474.430 1843.49 1992.819 2330.220 3578.490 4488.775 791.1783
NAs
0
0
0
For Impulse the optimal cutpoint is 2699.975 with a AUC of 0.5114,
sensitivity of 0.214 and specificity of 0.8451.
#other way to find threshold
#ROC object
roc_obj <- roc(response = all_hip_incident$LB.Injury,
predictor = all_hip_incident$Impulse, #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Impulse")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.4758
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

The Impulse threshold is 973.1775 with a sensitivity of 0.07587383
and a specificity of 0.9577465 and an AUC of 0.4886.
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret #2699.975
all_hip_incident <- all_hip_incident %>%
mutate(above_threshold=ifelse(Impulse>= 973.1775, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_hip_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_hip_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.7806 0.2791 6.380 1.78e-10 ***
above_threshold -0.5517 0.2871 -1.921 0.0547 .
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 1436.7 on 1362 degrees of freedom
Residual deviance: 1432.6 on 1361 degrees of freedom
AIC: 1436.6
Number of Fisher Scoring iterations: 4
odds.ratio=exp(-0.6211)
(1-odds.ratio)*100
[1] 46.2647
#GRAPHICS
#density plot
ggplot(all_hip_incident, aes(x = Impulse, fill = LB.Injury)) +
geom_density(alpha = 0.4) +
geom_vline(xintercept = 973.1775, linetype = "dashed", color = "red", size = 1) +
labs(title = "Density Plot: Impulse by Injury Status",
x = "Impulse",
y = "Density") +
scale_fill_manual(values = c("0" = "#000000", "1" = "#CFB87C"),
name = "Lower Body Injury", labels = c("No", "Yes")) #+

#scale_x_continuous(limits =c(0,3))
#boxplot
ggplot(all_hip_incident, aes(x = LB.Injury, y = Impulse, fill = LB.Injury)) +
geom_boxplot(alpha = 0.7) +
geom_hline(yintercept = 973.1775, linetype = "dashed", color = "red") +
labs(title = "Boxplot: Impulse by Injury Status",
x = "Lower Body Injury", y = "Impulse") +
scale_fill_manual(values = c("0" = "#000000", "1" ="#CFB87C"),
name = "LB Injury", labels = c("No", "Yes"))# +

#scale_y_continuous(limits =c(0,3))
#count distribution
injury_counts <- all_hip_incident %>%
mutate(
Threshold = ifelse(above_threshold == 1, "Above", "Below"),
Injury = ifelse(LB.Injury == 1, "Yes", "No")
) %>%
count(Threshold, Injury)
ggplot(injury_counts, aes(x = Threshold, y = n, fill = Injury)) +
geom_bar(stat = "identity", position = "stack") +
scale_fill_manual(values=c("Yes"='#CFB87C',"No"='#000000'))+
labs(
title = "Lower Body Injury Count Above vs Below the Impulse Threshold",
x = "Impulse Threshold",
y = "Count",
fill = "Lower Body Injury"
) +
theme_minimal()

#proportions distribution
threshold_summary <- all_hip_incident %>%
group_by(above_threshold, LB.Injury) %>%
summarise(count = n()) %>%
mutate(prop = count / sum(count))
`summarise()` has grouped output by 'above_threshold'. You can override using the
`.groups` argument.
ggplot(threshold_summary, aes(x = factor(above_threshold), y = prop, fill = factor(LB.Injury))) +
geom_bar(stat = "identity", position = "fill") +
scale_fill_manual(values = c("0" = "#000000", "1" = "#CFB87C"),
name = "Lower Body Injury", labels = c("No", "Yes")) +
labs(x = "Impulse Threshold", y = "Proportion",
title = "Lower Body Injury Proportions Above vs Below the Impulse Threshold") +
scale_x_discrete(labels = c("0" = "Below", "1" = "Above"))

#Hip.Abduction
all_hip_incident$LB.Injury <- as.factor(all_hip_incident$LB.Injury)
cp <- cutpointr(all_hip_incident, Hip.Abduction.MEAN.Imbalance, LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 1
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Hip.Abduction.MEAN.Imbalance
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.5148 1363 1063 300
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
1.4 0.0565 0.7139 0.8598 0.1967 914 149 241 59
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max. SD NAs
Overall 0 0.40 2.05 3.9 5.065297 6.40 13.5 50 4.890203 0
0 0 0.40 1.90 3.8 4.844667 6.45 11.5 50 4.814096 0
1 0 0.31 2.10 4.0 5.127563 6.40 13.5 50 4.911915 0
For Hip Abduction MEAN Imbalance the optimal cutpoint is 1.4 with a
AUC of 0.5143, sensitivity of 0.8602 and specificity of 0.1944.
#other way to find threshold
#ROC object
roc_obj <- roc(response = all_hip_incident$LB.Injury,
predictor = all_hip_incident$Hip.Abduction.MEAN.Imbalance, #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Hip.Abduction.MEAN.Imbalance")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.4852
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

The Hip.Abduction.MEAN.Imbalance threshold is 5.15 with a sensitivity
of 0.6419437 and a specificity of 0.3915493 and an AUC of 0.4857.
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_hip_incident <- all_hip_incident %>%
mutate(above_threshold=ifelse(Hip.Abduction.MEAN.Imbalance>= 1.4, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_hip_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_hip_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 0.9264 0.1538 6.023 1.72e-09 ***
above_threshold 0.4066 0.1700 2.392 0.0168 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 1436.7 on 1362 degrees of freedom
Residual deviance: 1431.2 on 1361 degrees of freedom
AIC: 1435.2
Number of Fisher Scoring iterations: 4
exp(0.3950)
[1] 1.484384
#GRAPHICS
#density plot
ggplot(all_hip_incident, aes(x = Hip.Abduction.MEAN.Imbalance, fill = LB.Injury)) +
geom_density(alpha = 0.4) +
geom_vline(xintercept = 1.4, linetype = "dashed", color = "red", size = 1) +
labs(title = "Density Plot: Hip Abduction Mean Imbalance by Injury Status",
x = "Hip Abduction Mean Imbalance",
y = "Density") +
scale_fill_manual(values = c("0" = "#000000", "1" = "#CFB87C"),
name = "Lower Body Injury", labels = c("No", "Yes")) +
scale_x_continuous(limits =c(0,30))
Warning: Removed 3 rows containing non-finite outside the scale range (`stat_density()`).

#boxplot
ggplot(all_hip_incident, aes(x = LB.Injury, y = Hip.Abduction.MEAN.Imbalance, fill = LB.Injury)) +
geom_boxplot(alpha = 0.7) +
geom_hline(yintercept = 1.4, linetype = "dashed", color = "red") +
labs(title = "Boxplot: Hip Abduction Mean Imbalance by Injury Status",
x = "Lower Body Injury", y = "Hip Abduction Mean Imbalance") +
scale_fill_manual(values = c("0" = "#000000", "1" ="#CFB87C"),
name = "LB Injury", labels = c("No", "Yes"))# +

#scale_y_continuous(limits =c(0,3))
#count distribution
injury_counts <- all_hip_incident %>%
mutate(
Threshold = ifelse(above_threshold == 1, "Above", "Below"),
Injury = ifelse(LB.Injury == 1, "Yes", "No")
) %>%
count(Threshold, Injury)
ggplot(injury_counts, aes(x = Threshold, y = n, fill = Injury)) +
geom_bar(stat = "identity", position = "stack") +
scale_fill_manual(values=c("Yes"='#CFB87C',"No"='#000000'))+
labs(
title = "Lower Body Injury Count Above vs Below the Hip Abduction Mean Imbalance Threshold",
x = "Hip Abduction Mean Imbalance Threshold",
y = "Count",
fill = "Lower Body Injury"
) +
theme_minimal()

#proportions distribution
threshold_summary <- all_hip_incident %>%
group_by(above_threshold, LB.Injury) %>%
summarise(count = n()) %>%
mutate(prop = count / sum(count))
`summarise()` has grouped output by 'above_threshold'. You can override using the
`.groups` argument.
ggplot(threshold_summary, aes(x = factor(above_threshold), y = prop, fill = factor(LB.Injury))) +
geom_bar(stat = "identity", position = "fill") +
scale_fill_manual(values = c("0" = "#000000", "1" = "#CFB87C"),
name = "Lower Body Injury", labels = c("No", "Yes")) +
labs(x = "Hip Abduction Mean Imbalance Threshold", y = "Proportion",
title = "Lower Body Injury Proportions Above vs Below the Hip Abduction Mean Imbalance Threshold") +
scale_x_discrete(labels = c("0" = "Below", "1" = "Above"))

#Hip.Adduction
all_hip_incident$LB.Injury <- as.factor(all_hip_incident$LB.Injury)
cp <- cutpointr(all_hip_incident, Hip.Adduction.MEAN.Imbalance, LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 1
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Hip.Adduction.MEAN.Imbalance
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.5074 1363 1063 300
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
4.5 0.0829 0.5143 0.4929 0.59 524 539 123 177
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max. SD NAs
Overall 0.0 0.4 2.0 4.3 5.162216 6.90 15.000 74.5 4.686724 0
0 0.1 0.5 2.1 4.1 5.033333 6.70 13.315 26.9 4.415709 0
1 0.0 0.4 2.0 4.3 5.198589 6.95 15.000 74.5 4.761784 0
For Hip Adduction MEAN Imbalance the optimal cutpoint is 4.5 with a
AUC of 0.5107, sensitivity of 0.4902 and specificity of 0.5915.
#other way to find threshold
#ROC object
roc_obj <- roc(response = all_hip_incident$LB.Injury,
predictor = all_hip_incident$Hip.Adduction.MEAN.Imbalance, #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Hip.Adduction.MEAN.Imbalance")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.4926
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

The Hip.Adduction.MEAN.Imbalance threshold is 16.2 with a sensitivity
of 0.9820972 and a specificity of 0.05070423 and an AUC of 0.4893.
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_hip_incident <- all_hip_incident %>%
mutate(above_threshold=ifelse(Hip.Adduction.MEAN.Imbalance>= 4.5, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_hip_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_hip_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.11357 0.08663 12.854 <2e-16 ***
above_threshold 0.33574 0.13245 2.535 0.0113 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 1436.7 on 1362 degrees of freedom
Residual deviance: 1430.2 on 1361 degrees of freedom
AIC: 1434.2
Number of Fisher Scoring iterations: 4
exp(0.33115)
[1] 1.392569
#GRAPHICS
#density plot
ggplot(all_hip_incident, aes(x = Hip.Adduction.MEAN.Imbalance, fill = LB.Injury)) +
geom_density(alpha = 0.4) +
geom_vline(xintercept = 4.5, linetype = "dashed", color = "red", size = 1) +
labs(title = "Density Plot: Hip Adduction Mean Imbalance by Injury Status",
x = "Hip Adduction Mean Imbalance",
y = "Density") +
scale_fill_manual(values = c("0" = "#000000", "1" = "#CFB87C"),
name = "Lower Body Injury", labels = c("No", "Yes")) +
scale_x_continuous(limits =c(0,35))
Warning: Removed 1 row containing non-finite outside the scale range (`stat_density()`).

#boxplot
ggplot(all_hip_incident, aes(x = LB.Injury, y = Hip.Adduction.MEAN.Imbalance, fill = LB.Injury)) +
geom_boxplot(alpha = 0.7) +
geom_hline(yintercept = 4.5, linetype = "dashed", color = "red") +
labs(title = "Boxplot: Hip Adduction Mean Imbalance by Injury Status",
x = "Lower Body Injury", y = "Hip Adduction Mean Imbalance") +
scale_fill_manual(values = c("0" = "#000000", "1" ="#CFB87C"),
name = "LB Injury", labels = c("No", "Yes"))# +

#scale_y_continuous(limits =c(0,3))
#count distribution
injury_counts <- all_hip_incident %>%
mutate(
Threshold = ifelse(above_threshold == 1, "Above", "Below"),
Injury = ifelse(LB.Injury == 1, "Yes", "No")
) %>%
count(Threshold, Injury)
ggplot(injury_counts, aes(x = Threshold, y = n, fill = Injury)) +
geom_bar(stat = "identity", position = "stack") +
scale_fill_manual(values=c("Yes"='#CFB87C',"No"='#000000'))+
labs(
title = "Lower Body Injury Count Above vs Below the Hip Adduction Mean Imbalance Threshold",
x = "Hip Adduction Mean Imbalance Threshold",
y = "Count",
fill = "Lower Body Injury"
) +
theme_minimal()

#proportions distribution
threshold_summary <- all_hip_incident %>%
group_by(above_threshold, LB.Injury) %>%
summarise(count = n()) %>%
mutate(prop = count / sum(count))
`summarise()` has grouped output by 'above_threshold'. You can override using the
`.groups` argument.
ggplot(threshold_summary, aes(x = factor(above_threshold), y = prop, fill = factor(LB.Injury))) +
geom_bar(stat = "identity", position = "fill") +
scale_fill_manual(values = c("0" = "#000000", "1" = "#CFB87C"),
name = "Lower Body Injury", labels = c("No", "Yes")) +
labs(x = "Hip Adduction Mean Imbalance Threshold", y = "Proportion",
title = "Lower Body Injury Proportions Above vs Below the Hip Adduction Mean Imbalance Threshold") +
scale_x_discrete(labels = c("0" = "Below", "1" = "Above"))

#NORDIC
all_nordic_incident$LB.Injury <- as.factor(all_nordic_incident$LB.Injury)
cp <- cutpointr(all_nordic_incident, Maximum.Nordic.Bilateral.Mean, LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 0
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Maximum.Nordic.Bilateral.Mean
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.4973 6050 1193 4857
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
302.54 0.0422 0.4747 0.5977 0.4445 713 480 2698 2159
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max. SD
Overall 60.750 236.9673 276.565 311.565 313.9760 347.690 397.625 624.38 55.85034
0 187.125 235.1250 279.005 315.290 313.1744 345.690 380.379 624.38 54.67630
1 60.750 237.3750 276.250 310.210 314.1729 348.565 398.250 624.38 56.13874
NAs
0
0
0
#other way to find threshold
#ROC object
roc_obj <- roc(response = all_nordic_incident$LB.Injury,
predictor = all_nordic_incident$Maximum.Nordic.Bilateral.Mean, #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Maximum.Nordic.Bilateral.Mean")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.4973
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_nordic_incident <- all_nordic_incident %>%
mutate(above_threshold=ifelse(Maximum.Nordic.Bilateral.Mean>= 301.46, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_nordic_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_nordic_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.49749 0.05081 29.473 <2e-16 ***
above_threshold -0.16037 0.06586 -2.435 0.0149 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 6007.4 on 6049 degrees of freedom
Residual deviance: 6001.5 on 6048 degrees of freedom
AIC: 6005.5
Number of Fisher Scoring iterations: 4
odds.ratio=exp(-0.18789)
(1-odds.ratio)*100
[1] 17.12941
#GRAPHICS
#density plot
ggplot(all_nordic_incident, aes(x = Maximum.Nordic.Bilateral.Mean, fill = LB.Injury)) +
geom_density(alpha = 0.4) +
geom_vline(xintercept = 301.46, linetype = "dashed", color = "red", size = 1) +
labs(title = "Density Plot: Maximum Nordic Bilateral Mean by Injury Status",
x = "Maximum Nordic Bilateral Mean",
y = "Density") +
scale_fill_manual(values = c("0" = "#000000", "1" = "#CFB87C"),
name = "Lower Body Injury", labels = c("No", "Yes")) #+

#scale_x_continuous(limits =c(0,35))
#boxplot
ggplot(all_nordic_incident, aes(x = LB.Injury, y = Maximum.Nordic.Bilateral.Mean, fill = LB.Injury)) +
geom_boxplot(alpha = 0.7) +
geom_hline(yintercept = 301.46, linetype = "dashed", color = "red") +
labs(title = "Boxplot: Maximum Nordic Bilateral Mean by Injury Status",
x = "Lower Body Injury", y = "Maximum Nordic Bilateral Mean") +
scale_fill_manual(values = c("0" = "#000000", "1" ="#CFB87C"),
name = "LB Injury", labels = c("No", "Yes"))# +

#scale_y_continuous(limits =c(0,3))
#count distribution
injury_counts <- all_nordic_incident %>%
mutate(
Threshold = ifelse(above_threshold == 1, "Above", "Below"),
Injury = ifelse(LB.Injury == 1, "Yes", "No")
) %>%
count(Threshold, Injury)
ggplot(injury_counts, aes(x = Threshold, y = n, fill = Injury)) +
geom_bar(stat = "identity", position = "stack") +
scale_fill_manual(values=c("Yes"='#CFB87C',"No"='#000000'))+
labs(
title = "Lower Body Injury Count Above vs Below the Maximum Nordic Bilateral Mean Threshold",
x = "Maximum Nordic Bilateral Mean Threshold",
y = "Count",
fill = "Lower Body Injury"
) +
theme_minimal()

#proportions distribution
threshold_summary <- all_nordic_incident %>%
group_by(above_threshold, LB.Injury) %>%
summarise(count = n()) %>%
mutate(prop = count / sum(count))
`summarise()` has grouped output by 'above_threshold'. You can override using the
`.groups` argument.
ggplot(threshold_summary, aes(x = factor(above_threshold), y = prop, fill = factor(LB.Injury))) +
geom_bar(stat = "identity", position = "fill") +
scale_fill_manual(values = c("0" = "#000000", "1" = "#CFB87C"),
name = "Lower Body Injury", labels = c("No", "Yes")) +
labs(x = "Maximum Nordic Bilateral Mean Threshold", y = "Proportion",
title = "Lower Body Injury Proportions Above vs Below the Maximum Nordic Bilateral Mean Threshold") +
scale_x_discrete(labels = c("0" = "Below", "1" = "Above"))

all_nordic_incident$LB.Injury <- as.factor(all_nordic_incident$LB.Injury)
cp <- cutpointr(all_nordic_incident, Impulse, LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 0
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Impulse
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.5229 6050 1193 4857
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
5939.035 0.0618 0.7357 0.1928 0.8691 230 963 636 4221
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max.
Overall 106.865 1387.485 2429.425 3736.98 3941.114 5069.295 7539.805 26190.12
0 425.165 1284.775 2548.370 3784.12 4054.398 5280.165 7741.263 12938.57
1 106.865 1437.188 2411.940 3731.59 3913.289 5031.445 7491.185 26190.12
SD NAs
1989.711 0
1974.143 0
1992.733 0
#ROC object
roc_obj <- roc(response = all_nordic_incident$LB.Injury,
predictor = all_nordic_incident$Impulse, #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Impulse")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.5229
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_nordic_incident <- all_nordic_incident %>%
mutate(above_threshold=ifelse(Impulse>= 5939.035, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_nordic_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_nordic_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.47777 0.03571 41.381 < 2e-16 ***
above_threshold -0.46065 0.08483 -5.431 5.62e-08 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 6007.4 on 6049 degrees of freedom
Residual deviance: 5979.4 on 6048 degrees of freedom
AIC: 5983.4
Number of Fisher Scoring iterations: 4
odds.ratio=exp(-0.48044)
(1-odds.ratio)*100
[1] 38.14888
all_nordic_incident$LB.Injury <- as.factor(all_nordic_incident$LB.Injury)
cp <- cutpointr(all_nordic_incident, Nordic.MAX.Imbalance, LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 1
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Nordic.MAX.Imbalance
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.5013 6050 4857 1193
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
10.7 0.0296 0.3732 0.281 0.7485 1365 3492 300 893
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max. SD NAs
Overall 0 0.7 3.3 6.4 8.174512 11.2 20.60 59.7 6.883408 0
0 0 0.9 3.3 6.3 8.144761 10.8 20.70 59.7 6.962796 0
1 0 0.7 3.3 6.4 8.181820 11.3 20.52 59.7 6.864471 0
#ROC object
roc_obj <- roc(response = all_nordic_incident$LB.Injury,
predictor = all_nordic_incident$Nordic.MAX.Imbalance, #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Impulse")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.4987
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_nordic_incident <- all_nordic_incident %>%
mutate(above_threshold=ifelse(Nordic.MAX.Imbalance>= 10.7 , 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_nordic_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_nordic_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.36364 0.03750 36.365 <2e-16 ***
above_threshold 0.15148 0.07397 2.048 0.0406 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 6007.4 on 6049 degrees of freedom
Residual deviance: 6003.2 on 6048 degrees of freedom
AIC: 6007.2
Number of Fisher Scoring iterations: 4
#CMJ 1. Relative.Concentric.Power.Bilateral
#way 1 to find threshold
all_CMJ_incident$LB.Injury <- as.factor(all_CMJ_incident$LB.Injury)
#Error: "Relative.Concentric.Power.Bilateral", :method should be a function
cp <- cutpointr(all_CMJ_incident, Relative.Concentric.Power.Bilateral, LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 1
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Relative.Concentric.Power.Bilateral
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.5028 3471 2581 890
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
10.3 0.0401 0.618 0.721 0.3191 1861 720 606 284
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max. SD NAs
Overall -1023.4 9.5 10.1 10.7 3.615478 11.4 12.3 19.4 74.18229 0
0 -768.4 9.5 10.1 10.7 9.172528 11.5 12.2 19.4 34.20699 0
1 -1023.4 9.4 10.1 10.7 1.699254 11.4 12.3 14.0 83.56926 0
For Relative Concentric Power Bilateral the optimal cutpoint is 10.3
with a AUC of 0.5028, sensitivity of 0.721 and specificity of
0.3191.
#way 2 to find threshold
#ROC object
roc_obj <- roc(response = all_CMJ_incident$LB.Injury,
predictor = all_CMJ_incident$Relative.Concentric.Power.Bilateral, #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Relative Concentric Bilateral Power")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.4972
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

For Relative Concentric Power Bilateral the optimal threshold was
10.85, with an AUC of 0.4972, sensitivity 0.5625726, and specificity
0.4707865.
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_CMJ_incident <- all_CMJ_incident %>%
mutate(above_threshold=ifelse(Relative.Concentric.Power.Bilateral>= 10.3, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_CMJ_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_CMJ_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 0.93028 0.07007 13.276 <2e-16 ***
above_threshold 0.19171 0.08425 2.276 0.0229 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 3951.9 on 3470 degrees of freedom
Residual deviance: 3946.7 on 3469 degrees of freedom
AIC: 3950.7
Number of Fisher Scoring iterations: 4
- Eccentric.Concentric.Mean.Force.Ratio
all_CMJ_incident$LB.Injury <- as.factor(all_CMJ_incident$LB.Injury)
cp <- cutpointr(all_CMJ_incident, Eccentric.Concentric.Mean.Force.Ratio , LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 1
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Eccentric.Concentric.Mean.Force.Ratio
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.4938 3471 2581 890
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
53.5025 0.06 0.486 0.4398 0.6202 1135 1446 338 552
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max. SD
Overall 40.5825 45.5845 49.6305 52.4310 52.99744 56.13150 61.19533 102.89 5.240016
0 40.5825 46.1481 50.1495 52.1500 53.07468 56.22944 60.77665 102.89 4.991743
1 40.5825 45.5290 49.4815 52.5175 52.97081 56.02700 61.65250 102.89 5.323622
NAs
0
0
0
For Eccentric Concentric Mean Force Ratio the optimal cutpoint is
53.5025 with a AUC of 0.4938, sensitivity of 0.49398 and specificity of
0.6202.
#ROC object
roc_obj <- roc(response = all_CMJ_incident$LB.Injury,
predictor = all_CMJ_incident$Eccentric.Concentric.Mean.Force.Ratio , #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Eccentric Concentric Mean Force Ratio")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.5062
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

For Eccentric Concentric Mean Force Ratio the optimal threshold is
47.7145 with a AUC of 0.5062, sensitivity of 0.1666021 and specificity
of 0.9157303.
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_CMJ_incident <- all_CMJ_incident %>%
mutate(above_threshold=ifelse(Eccentric.Concentric.Mean.Force.Ratio>= 47.7145, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_CMJ_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_CMJ_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.7463 0.1251 13.96 < 2e-16 ***
above_threshold -0.7758 0.1317 -5.89 3.87e-09 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 3951.9 on 3470 degrees of freedom
Residual deviance: 3912.1 on 3469 degrees of freedom
AIC: 3916.1
Number of Fisher Scoring iterations: 4
- Maximum Jump Height
all_CMJ_incident$LB.Injury <- as.factor(all_CMJ_incident$LB.Injury)
cp <- cutpointr(all_CMJ_incident, Max.Jump.Height..cm. , LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 1
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Max.Jump.Height..cm.
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.5063 3471 2581 890
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
41.379 0.0575 0.3178 0.0957 0.9618 247 2334 34 856
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max. SD NAs
Overall 11.18 24.1660 30.239 33.658 33.65939 37.623 42.382 48.345 5.528537 0
0 11.18 25.2253 30.037 33.658 33.62400 37.623 40.953 48.345 4.959533 0
1 11.18 24.1660 30.401 33.658 33.67159 37.623 42.671 48.345 5.712470 0
For Maximum Jump Height the optimal cutpoint is 41.379 with a AUC of
0.5063, sensitivity of 0.0957 and specificity of 09618.
#ROC object
roc_obj <- roc(response = all_CMJ_incident$LB.Injury,
predictor = all_CMJ_incident$Max.Jump.Height..cm. , #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Maximum Jump Height")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.4937
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

For Maximum Jump Height the optimal threshold is 24.6 with a AUC of
0.4937, sensitivity of 0.07245254 and specificity of 0.9595506.
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_CMJ_incident <- all_CMJ_incident %>%
mutate(above_threshold=ifelse(Max.Jump.Height..cm.>= 41.379, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_CMJ_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_CMJ_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.00307 0.03996 25.103 < 2e-16 ***
above_threshold 0.97996 0.18723 5.234 1.66e-07 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 3951.9 on 3470 degrees of freedom
Residual deviance: 3917.9 on 3469 degrees of freedom
AIC: 3921.9
Number of Fisher Scoring iterations: 4
- Maximum Concentric RFD
all_CMJ_incident$LB.Injury <- as.factor(all_CMJ_incident$LB.Injury)
cp <- cutpointr(all_CMJ_incident, Max.Concentric.RPD..N.s. , LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 0
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Max.Concentric.RPD..N.s.
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.527 3471 890 2581
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
15784.34 0.0997 0.5238 0.6034 0.4963 537 353 1300 1281
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max.
Overall 5819.763 10225.86 13141.06 16154.14 17191.75 19860.65 28623.75 42854.54
0 5819.763 10363.00 13441.98 16951.24 17375.75 20098.94 27831.35 42854.54
1 5819.763 10225.86 13040.81 15857.07 17128.30 19775.72 28889.31 42854.54
SD NAs
5732.665 0
5433.096 0
5832.070 0
For Maximum Concentric RFD the optimal cutpoint is 15784.34 with a
AUC of 0.527, sensitivity of 0.6034 and specificity of 0.4963.
#ROC object
roc_obj <- roc(response = all_CMJ_incident$LB.Injury,
predictor = all_CMJ_incident$Max.Concentric.RPD..N.s. , #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Maximum Concentric RFD")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.527
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

For Maximum Concentric RFD the optimal threshold is 15780.66 with a
AUC of 0.527, sensitivity of 0.496313 and specificity of 0.6033708.
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_CMJ_incident <- all_CMJ_incident %>%
mutate(above_threshold=ifelse(Max.Concentric.RPD..N.s.>= 15784.34, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_CMJ_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_CMJ_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.28893 0.06011 21.442 < 2e-16 ***
above_threshold -0.40481 0.07902 -5.123 3.01e-07 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 3951.9 on 3470 degrees of freedom
Residual deviance: 3925.3 on 3469 degrees of freedom
AIC: 3929.3
Number of Fisher Scoring iterations: 4
- Eccentric Mean Braking Force
all_CMJ_incident$LB.Injury <- as.factor(all_CMJ_incident$LB.Injury)
cp <- cutpointr(all_CMJ_incident, Eccentric.Mean.Braking.Force..N. , LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 0
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Eccentric.Mean.Braking.Force..N.
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.5989 3471 890 2581
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
783.517 0.1718 0.5232 0.7146 0.4572 636 254 1401 1180
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max.
Overall 534.5985 648.5150 724.0920 816.8525 822.0157 897.5575 1017.270 1412.818
0 534.5985 660.6918 762.7141 855.4055 845.8658 917.4554 1014.490 1412.818
1 534.5985 645.7673 718.4135 804.8955 813.7916 886.1270 1044.267 1412.818
SD NAs
126.5218 0
113.5831 0
129.6941 0
For Eccentric Mean Braking Force the optimal cutpoint is 783.517 with
a AUC of 0.5989, sensitivity of 0.7146 and specificity of 0.4572.
#ROC object
roc_obj <- roc(response = all_CMJ_incident$LB.Injury,
predictor = all_CMJ_incident$Eccentric.Mean.Braking.Force..N. , #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Eccentric Mean Braking Force")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.5989
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

For Eccentric Mean Braking Force the optimal threshold is 783.4963
with a AUC of 0.5989, sensitivity of 0.4571871 and specificity of
0.7146067.
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_CMJ_incident <- all_CMJ_incident %>%
mutate(above_threshold=ifelse(Eccentric.Mean.Braking.Force..N.>= 783.517, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_CMJ_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_CMJ_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.53594 0.06917 22.205 <2e-16 ***
above_threshold -0.74619 0.08409 -8.874 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 3951.9 on 3470 degrees of freedom
Residual deviance: 3868.8 on 3469 degrees of freedom
AIC: 3872.8
Number of Fisher Scoring iterations: 4
- Maximum VALD RSI
all_CMJ_incident$LB.Injury <- as.factor(all_CMJ_incident$LB.Injury)
cp <- cutpointr(all_CMJ_incident, Max.RSI.Modified.VALD , LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 0
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Max.RSI.Modified.VALD
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.5263 3471 890 2581
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
0.4 0.0622 0.4702 0.6562 0.406 584 306 1533 1048
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max. SD NAs
Overall 0.075 0.246 0.365 0.4300 0.4381042 0.50900 0.613 1.650 0.1317570 0
0 0.075 0.259 0.373 0.4395 0.4419275 0.52075 0.611 1.650 0.1233451 0
1 0.075 0.238 0.363 0.4260 0.4367858 0.50500 0.614 1.552 0.1345335 0
For Maximum VALD RSI the optimal cutpoint is 0.4 with a AUC of
0.5263, sensitivity of 0.6562 and specificity of 0.406.
#ROC object
roc_obj <- roc(response = all_CMJ_incident$LB.Injury,
predictor = all_CMJ_incident$Max.RSI.Modified.VALD , #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Maximum VALD RSI")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.5263
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

For Maximum VALD RSI the optimal threshold is 0.3995 with a AUC of
0.5263, sensitivity of 0.4060442 and specificity of 0.6561798.
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_CMJ_incident <- all_CMJ_incident %>%
mutate(above_threshold=ifelse(Max.RSI.Modified.VALD>= 0.3995, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_CMJ_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_CMJ_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.23105 0.06498 18.946 < 2e-16 ***
above_threshold -0.26597 0.08116 -3.277 0.00105 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 3951.9 on 3470 degrees of freedom
Residual deviance: 3941.0 on 3469 degrees of freedom
AIC: 3945
Number of Fisher Scoring iterations: 4
#Hop Jump 1.Maximum Jump Height
all_hopjump_incident$LB.Injury <- as.factor(all_hopjump_incident$LB.Injury)
cp <- cutpointr(all_hopjump_incident, Max.Jump.Height..cm. , LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 0
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Max.Jump.Height..cm.
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.533 5597 1121 4476
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
25.489 0.0605 0.5326 0.5263 0.5342 590 531 2085 2391
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max. SD NAs
Overall 2.234 13.785 21.112 25.155 24.95184 28.637 35.218 174.759 7.048923 0
0 4.348 14.004 21.727 25.751 25.58909 29.232 35.481 174.759 8.022066 0
1 2.234 13.349 20.943 25.044 24.79225 28.479 34.694 174.759 6.774996 0
For Maximum Jump Height the optimal cutpoint is 25.489 with a AUC of
0.533, sensitivity of 0.5263 and specificity of 0.5342.
#ROC object
roc_obj <- roc(response = all_hopjump_incident$LB.Injury,
predictor = all_hopjump_incident$Max.Jump.Height..cm. , #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Maximum Jump Height")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.533
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

For Maximum Jump Height the optimal threshold is 25.4335 with a AUC
of 0.533, sensitivity of 0.5341823 and specificity of 0.5263158.
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_hopjump_incident <- all_hopjump_incident %>%
mutate(above_threshold=ifelse(Max.Jump.Height..cm.>= 25.489, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_hopjump_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_hopjump_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.50470 0.04797 31.365 < 2e-16 ***
above_threshold -0.24230 0.06690 -3.622 0.000293 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 5605.9 on 5596 degrees of freedom
Residual deviance: 5592.8 on 5595 degrees of freedom
AIC: 5596.8
Number of Fisher Scoring iterations: 4
2.Mean RSI Flight Contact Time
all_hopjump_incident$LB.Injury <- as.factor(all_hopjump_incident$LB.Injury)
cp <- cutpointr(all_hopjump_incident, Mean.RSI..Flight.Contact.Time. , LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 1
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Mean.RSI..Flight.Contact.Time.
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.5086 5597 4476 1121
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
2.441 0.0404 0.4492 0.4017 0.6387 1798 2678 405 716
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max. SD NAs
Overall 0.667 1.30700 1.946 2.311 2.252693 2.610 2.9626 3.641 0.4919100 0
0 0.707 1.30700 1.957 2.290 2.241572 2.596 2.9260 3.641 0.4874101 0
1 0.667 1.30675 1.944 2.311 2.255478 2.615 2.9730 3.641 0.4930453 0
For Mean RSI Flight Contact Time the optimal cutpoint is 2.441 with a
AUC of 0.5086, sensitivity of 0.4017 and specificity of 0.6387.
#ROC object
roc_obj <- roc(response = all_hopjump_incident$LB.Injury,
predictor = all_hopjump_incident$Mean.RSI..Flight.Contact.Time. , #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Mean RSI Flight Contact Time")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.4914
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

For Mean RSI Flight Contact Time the optimal threshold is 1.8 with a
AUC of 0.4914, sensitivity of 0.1646559 and specificity of
0.8599465.
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_hopjump_incident <- all_hopjump_incident %>%
mutate(above_threshold=ifelse(Mean.RSI..Flight.Contact.Time.>= 2.441, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_hopjump_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_hopjump_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.31915 0.04207 31.354 <2e-16 ***
above_threshold 0.17140 0.06925 2.475 0.0133 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 5605.9 on 5596 degrees of freedom
Residual deviance: 5599.8 on 5595 degrees of freedom
AIC: 5603.8
Number of Fisher Scoring iterations: 4
3.Best Contact Time
all_hopjump_incident$LB.Injury <- as.factor(all_hopjump_incident$LB.Injury)
cp <- cutpointr(all_hopjump_incident, Best.Contact.Time..ms. , LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 0
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Best.Contact.Time..ms.
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.5442 5597 1121 4476
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
0.184 0.1176 0.4772 0.6949 0.4227 779 342 2584 1892
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max. SD NAs
Overall 0.052 0.152 0.170 0.192 0.2052462 0.220 0.3052 0.580 0.05585130 0
0 0.052 0.154 0.176 0.202 0.2072221 0.220 0.2850 0.576 0.05334666 0
1 0.052 0.152 0.170 0.190 0.2047513 0.219 0.3080 0.580 0.05645613 0
For Best Contact Time the optimal cutpoint is 0.184 with a AUC of
0.5442, sensitivity of 0.6949 and specificity of 0.4227.
#ROC object
roc_obj <- roc(response = all_hopjump_incident$LB.Injury,
predictor = all_hopjump_incident$Best.Contact.Time..ms. , #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Best Contact Time")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.5442
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

For Best Contact Time the optimal threshold is 0.1835 with a AUC of
0.5442 , sensitivity of 0.4226988 and specificity of 0.6949153.
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_hopjump_incident <- all_hopjump_incident %>%
mutate(above_threshold=ifelse(Best.Contact.Time..ms.>= 0.184, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_hopjump_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_hopjump_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.71058 0.05876 29.112 < 2e-16 ***
above_threshold -0.51150 0.07158 -7.146 8.93e-13 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 5605.9 on 5596 degrees of freedom
Residual deviance: 5552.9 on 5595 degrees of freedom
AIC: 5556.9
Number of Fisher Scoring iterations: 4
#Isometric Mid Thigh Pull 1. Peak Vertical Force
all_IMTP_incident$LB.Injury <- as.factor(all_IMTP_incident$LB.Injury)
cp <- cutpointr(all_IMTP_incident, Peak.Vertical.Force...BM..N.kg. , LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 0
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Peak.Vertical.Force...BM..N.kg.
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.5116 1552 308 1244
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
30.813 0.0811 0.3711 0.8214 0.2596 253 55 921 323
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max. SD NAs
Overall 15.429 19.79800 31.690 53.097 50.23716 66.0500 79.7690 99.339 20.31384 0
0 15.429 20.21305 37.594 53.306 51.21625 64.2515 77.6291 94.577 18.63913 0
1 15.429 19.34760 28.207 52.968 49.99475 66.5820 79.7690 99.339 20.70748 0
ForPeak Vertical Force the optimal cutpoint is 30.813 with a AUC of
0.5116, sensitivity of 0.8214 and specificity of 0.2596.
#ROC object
roc_obj <- roc(response = all_IMTP_incident$LB.Injury,
predictor = all_IMTP_incident$Peak.Vertical.Force...BM..N.kg. , #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Peak Vertical Force")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.5116
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

For Peak Vertical Forc the optimal threshold is 30.5455 with a AUC of
0.5116 , sensitivity of 0.2596463 and specificity of 0.8214286.
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_IMTP_incident <- all_IMTP_incident %>%
mutate(above_threshold=ifelse(Peak.Vertical.Force...BM..N.kg.>= 30.813, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_IMTP_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_IMTP_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.7703 0.1459 12.136 <2e-16 ***
above_threshold -0.4782 0.1622 -2.948 0.0032 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 1546.6 on 1551 degrees of freedom
Residual deviance: 1537.3 on 1550 degrees of freedom
AIC: 1541.3
Number of Fisher Scoring iterations: 4
2.RPD at 200ms
all_IMTP_incident$LB.Injury <- as.factor(all_IMTP_incident$LB.Injury)
cp <- cutpointr(all_IMTP_incident, RFD...200ms..N.s. , LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 1
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: RFD...200ms..N.s.
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.5208 1552 1244 308
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
4032.637 0.0799 0.3956 0.3006 0.7792 374 870 68 240
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max.
Overall 163.605 754.960 1645.692 2485.000 3187.018 4281.361 8207.418 10407.179
0 163.605 639.274 1545.000 2442.225 3112.494 3697.168 8859.101 10407.179
1 163.605 815.000 1693.814 2516.359 3205.470 4494.561 7703.887 9098.845
SD NAs
2130.324 0
2274.026 0
2093.775 0
For RPD at 200ms the optimal cutpoint is 4032.637 with a AUC of
0.5208, sensitivity of 0.3006 and specificity of 0.7792.
#ROC object
roc_obj <- roc(response = all_IMTP_incident$LB.Injury,
predictor = all_IMTP_incident$RFD...200ms..N.s. , #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - RPD at 200ms")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.4792
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

For RPD at 200ms the optimal threshold is 8357.859 with a AUC of
0.4792 , sensitivity of 0.9766881 and specificity of 0.07792208.
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_IMTP_incident <- all_IMTP_incident %>%
mutate(above_threshold=ifelse(RFD...200ms..N.s.>= 8357.859, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_IMTP_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_IMTP_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.45353 0.06591 22.053 < 2e-16 ***
above_threshold -1.26428 0.28371 -4.456 8.34e-06 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 1546.6 on 1551 degrees of freedom
Residual deviance: 1528.3 on 1550 degrees of freedom
AIC: 1532.3
Number of Fisher Scoring iterations: 4
- Force at 200ms
all_IMTP_incident$LB.Injury <- as.factor(all_IMTP_incident$LB.Injury)
cp <- cutpointr(all_IMTP_incident, Force.at.200ms...BM..N.kg. , LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 1
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Force.at.200ms...BM..N.kg.
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.507 1552 1244 308
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
24.254 0.0792 0.4381 0.3714 0.7078 462 782 90 218
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max. SD
Overall 11.507 13.8694 17.04575 20.108 23.27384 28.847 40.66500 55.628 8.557926
0 11.817 13.9933 17.48400 19.799 22.99356 27.422 40.67475 48.157 8.372799
1 11.507 13.8910 16.98975 20.288 23.34324 28.866 40.22200 55.628 8.605049
NAs
0
0
0
For Force at 200ms the optimal cutpoint is 24.254 with a AUC of
0.507, sensitivity of 0.3714 and specificity of 0.7078.
#ROC object
roc_obj <- roc(response = all_IMTP_incident$LB.Injury,
predictor = all_IMTP_incident$Force.at.200ms...BM..N.kg. , #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Force at 200ms")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.493
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

For Force at 200ms the optimal threshold is 17.6205 with a AUC of
0.493 , sensitivity of 0.312701 and specificity of 0.7402597.
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_IMTP_incident <- all_IMTP_incident %>%
mutate(above_threshold=ifelse(Force.at.200ms...BM..N.kg.>= 24.254, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_IMTP_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_IMTP_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.27736 0.07659 16.68 < 2e-16 ***
above_threshold 0.35840 0.13835 2.59 0.00959 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 1546.6 on 1551 degrees of freedom
Residual deviance: 1539.7 on 1550 degrees of freedom
AIC: 1543.7
Number of Fisher Scoring iterations: 4
- DSI
all_IMTP_incident$LB.Injury <- as.factor(all_IMTP_incident$LB.Injury)
cp <- cutpointr(all_IMTP_incident, DSI , LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 1
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: DSI
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.5005 1552 1244 308
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
0.59 0.0862 0.3537 0.2291 0.8571 285 959 44 264
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max. SD NAs
Overall 0.16 0.19 0.24 0.29 0.3855348 0.4700 0.84 1.26 0.2076250 0
0 0.19 0.21 0.25 0.29 0.3637013 0.4425 0.70 0.89 0.1653048 0
1 0.16 0.18 0.23 0.29 0.3909405 0.5050 0.87 1.26 0.2165490 0
For DSI the optimal cutpoint is 0.59 with a AUC of 0.5005,
sensitivity of 0.2291 and specificity of 0.8571.
#ROC object
roc_obj <- roc(response = all_IMTP_incident$LB.Injury,
predictor = all_IMTP_incident$DSI , #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Dynamic Strength Index")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.4995
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

For DSI the optimal threshold is 0.235 with a AUC of 0.4995 ,
sensitivity of 0.2580386 and specificity of 0.8116883.
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_IMTP_incident <- all_IMTP_incident %>%
mutate(above_threshold=ifelse(DSI>= 0.59, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_IMTP_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_IMTP_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.2899 0.0695 18.560 < 2e-16 ***
above_threshold 0.5784 0.1763 3.281 0.00103 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 1546.6 on 1551 degrees of freedom
Residual deviance: 1534.8 on 1550 degrees of freedom
AIC: 1538.8
Number of Fisher Scoring iterations: 4
#Single Leg Jump 1.Maximum Jump Height
all_SLJ_incident$LB.Injury <- as.factor(all_SLJ_incident$LB.Injury)
cp <- cutpointr(all_SLJ_incident, Max.Jump.Height..cm. , LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 1
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Max.Jump.Height..cm.
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.6147 461 389 72
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
19.223 0.2514 0.4447 0.3625 0.8889 141 248 8 64
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max. SD NAs
Overall 8.076 13.349 15.449 17.5150 17.81091 20.0080 24.057 26.127 3.259416 0
0 10.191 13.349 14.506 16.7365 16.79581 18.3605 21.452 26.127 2.826625 0
1 8.076 13.610 15.536 17.5150 17.99880 20.2060 24.166 25.939 3.302507 0
For Maximum Jump Height the optimal cutpoint is 19.223 with a AUC of
0.6147, sensitivity of 0.3625 and specificity of 0.8889.
#ROC object
roc_obj <- roc(response = all_SLJ_incident$LB.Injury,
predictor = all_SLJ_incident$Max.Jump.Height..cm. , #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Maximum Jump Height")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.3853
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

For Maximum Jump Height the optimal threshold is 24.953 with a AUC of
0.3853 , sensitivity of 0.9897172 and specificity of 0.02777778.
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_SLJ_incident <- all_SLJ_incident %>%
mutate(above_threshold=ifelse(Max.Jump.Height..cm.>= 19.223, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_SLJ_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_SLJ_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.3545 0.1402 9.661 < 2e-16 ***
above_threshold 1.5148 0.3895 3.889 0.000101 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 399.49 on 460 degrees of freedom
Residual deviance: 378.99 on 459 degrees of freedom
AIC: 382.99
Number of Fisher Scoring iterations: 5
2.Jump Height Flight Time
all_SLJ_incident$LB.Injury <- as.factor(all_SLJ_incident$LB.Injury)
cp <- cutpointr(all_SLJ_incident, Jump.Height..Flight.Time...cm. , LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 1
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Jump.Height..Flight.Time...cm.
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.5904 461 389 72
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
17.027 0.2015 0.4121 0.3265 0.875 127 262 9 63
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max.
Overall 6.54475 10.80117 13.63300 15.10650 15.60223 17.45817 20.49267 24.92950
0 8.93025 10.58817 13.45133 14.81125 14.88945 16.50425 19.26850 24.92950
1 6.54475 10.96050 13.68300 15.67100 15.73416 17.83983 20.49267 23.54233
SD NAs
2.970292 0
2.865081 0
2.974221 0
For Jump Height Flight Time the optimal cutpoint is 17.027 with a AUC
of 0.5904, sensitivity of 0.3265 and specificity of 0.875.
#ROC object
roc_obj <- roc(response = all_SLJ_incident$LB.Injury,
predictor = all_SLJ_incident$Jump.Height..Flight.Time...cm. , #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Jump Height Flight Time")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.4096
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

For Jump Height Flight Time the optimal threshold is 23.40658 with a
AUC of 0.4096 , sensitivity of 0.9897172 and specificity of 0.02777778.
17.027
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_SLJ_incident <- all_SLJ_incident %>%
mutate(above_threshold=ifelse(Jump.Height..Flight.Time...cm.>= 17.027, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_SLJ_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_SLJ_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.4252 0.1403 10.157 < 2e-16 ***
above_threshold 1.2218 0.3724 3.281 0.00103 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 399.49 on 460 degrees of freedom
Residual deviance: 385.91 on 459 degrees of freedom
AIC: 389.91
Number of Fisher Scoring iterations: 5
3.Landing RPD
all_SLJ_incident$LB.Injury <- as.factor(all_SLJ_incident$LB.Injury)
cp <- cutpointr(all_SLJ_incident, Landing.RFD..N.s. , LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 1
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Landing.RFD..N.s.
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.5347 461 389 72
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
31061.16 0.1793 0.5271 0.4987 0.6806 194 195 23 49
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max.
Overall 15415.74 22156.75 25896.93 30039.20 33569.95 36070.15 65348.99 94599.51
0 19749.20 22438.69 25795.79 28660.47 33911.47 35126.72 66784.58 86171.55
1 15415.74 22238.03 26339.81 30063.18 33506.74 36070.15 65348.99 94599.51
SD NAs
12836.31 0
14369.26 0
12551.43 0
For Landing RPD the optimal cutpoint is =31061.16 with a AUC of
0.5347, sensitivity of 0.4987 and specificity of 0.6806.
#ROC object
roc_obj <- roc(response = all_SLJ_incident$LB.Injury,
predictor = all_SLJ_incident$Landing.RFD..N.s. , #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Landing RPD")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.4653
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

For Landing RPD the optimal threshold is 24395.01 with a AUC of
0.4653 , sensitivity of 0.1491003 and specificity of 0.9444444.
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_SLJ_incident <- all_SLJ_incident %>%
mutate(above_threshold=ifelse(Landing.RFD..N.s.>= 31061.16, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_SLJ_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_SLJ_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.4065 0.1594 8.824 <2e-16 ***
above_threshold 0.6998 0.2723 2.569 0.0102 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 399.49 on 460 degrees of freedom
Residual deviance: 392.55 on 459 degrees of freedom
AIC: 396.55
Number of Fisher Scoring iterations: 4
4.Maximum Concentric Peak Force
all_SLJ_incident$LB.Injury <- as.factor(all_SLJ_incident$LB.Injury)
cp <- cutpointr(all_SLJ_incident, Max.Concentric.Peak.Force..N. , LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 1
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Max.Concentric.Peak.Force..N.
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.546 461 389 72
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
1243.319 0.176 0.744 0.8149 0.3611 317 72 46 26
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max.
Overall 967.511 1100.467 1275.915 1414.809 1437.622 1614.146 1794.600 2341.291
0 1062.075 1116.511 1224.982 1356.709 1419.043 1642.242 1898.815 2341.291
1 967.511 1098.233 1298.767 1436.538 1441.061 1601.038 1794.600 2341.291
SD NAs
219.0502 0
252.3892 0
212.4962 0
For Maximum Concentric Peak Force the optimal cutpoint is 1243.319
with a AUC of 0.546, sensitivity of 0.8149 and specificity of
0.3611.
#ROC object
roc_obj <- roc(response = all_SLJ_incident$LB.Injury,
predictor = all_SLJ_incident$Max.Concentric.Peak.Force..N. , #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Maximum Concentric Peak Force")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.454
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

For Maximum Concentric Peak Force the optimal threshold is 1678.094
with a AUC of 0.454 , sensitivity of 0.8843188 and specificity of
0.1944444.
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_SLJ_incident <- all_SLJ_incident %>%
mutate(above_threshold=ifelse(Max.Concentric.Peak.Force..N.>= 1243.319, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_SLJ_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_SLJ_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.0186 0.2288 4.452 8.52e-06 ***
above_threshold 0.9117 0.2779 3.280 0.00104 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 399.49 on 460 degrees of freedom
Residual deviance: 389.35 on 459 degrees of freedom
AIC: 393.35
Number of Fisher Scoring iterations: 4
5.Concentric Impulse
all_SLJ_incident$LB.Injury <- as.factor(all_SLJ_incident$LB.Injury)
cp <- cutpointr(all_SLJ_incident, Concentric.Impulse..Ns. , LB.Injury, method=maximize_metric, metric=youden)
Assuming the positive class is 1
Assuming the positive class has higher x values
plot(cp)



summary(cp)
Method: maximize_metric
Predictor: Concentric.Impulse..Ns.
Outcome: LB.Injury
Direction: >=
AUC n n_pos n_neg
0.5224 461 389 72
optimal_cutpoint youden acc sensitivity specificity tp fn fp tn
123.136 0.1259 0.3102 0.1954 0.9306 76 313 5 67
Predictor summary:
Data Min. 5% 1st Qu. Median Mean 3rd Qu. 95% Max.
Overall 69.80725 88.57400 99.9160 112.3837 111.4520 119.7969 138.3845 149.1775
0 86.81025 87.98621 99.8395 110.3307 110.2643 118.9905 135.7452 149.1775
1 69.80725 88.57400 100.1335 112.3837 111.6719 120.2831 138.3845 147.7083
SD NAs
14.84351 0
13.08089 0
15.15237 0
For Concentric Impulse the optimal cutpoint is 123.136 with a AUC of
0.5224, sensitivity of 0.1954 and specificity of 0.9306.
#ROC object
roc_obj <- roc(response = all_SLJ_incident$LB.Injury,
predictor = all_SLJ_incident$Concentric.Impulse..Ns. , #power
direction = ">") # use "<" if higher values= high risk predict 'No'
Setting levels: control = 0, case = 1
# if > rel. con. power then lower risk
#plot curve
plot(roc_obj, main = "ROC Curve - Concentric Impulse")

auc_value <- auc(roc_obj)
print(auc_value)
Area under the curve: 0.4776
best_coords <- coords(roc_obj, "best", ret = c("threshold", "sensitivity", "specificity"), best.method = "youden")
best_coords
#plot + threshold
plot(roc_obj, main = "ROC Curve with Optimal Threshold")
abline(a = 0, b = 1, lty = 2, col = "gray")
points(1 - best_coords["specificity"], best_coords["sensitivity"], col = '#CFB87C', pch = 19)
text(1 - best_coords["specificity"], best_coords["sensitivity"],
labels = paste("Threshold =", round(best_coords["threshold"], 2)), pos = 4)

For Concentric Impulse the optimal threshold is 94.20375 with a AUC
of 0.4776 , sensitivity of 0.1285347 and specificity of 0.9305556.
123.136
#look at/discover/create more meaningful thresholds for strength metrics relating to LB injury risk, then test confirm threshold is valuable + interpret
all_SLJ_incident <- all_SLJ_incident %>%
mutate(above_threshold=ifelse(Concentric.Impulse..Ns.>= 123.136, 1,0))#add newfound threshold
#Does being above the threshold relate to lower body injury risk?
model <- glm(LB.Injury~ above_threshold,data=all_SLJ_incident, family="binomial")
summary(model)
Call:
glm(formula = LB.Injury ~ above_threshold, family = "binomial",
data = all_SLJ_incident)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.5415 0.1346 11.452 <2e-16 ***
above_threshold 1.1798 0.4809 2.453 0.0142 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 399.49 on 460 degrees of freedom
Residual deviance: 391.51 on 459 degrees of freedom
AIC: 395.51
Number of Fisher Scoring iterations: 5
All Time
1. Basketball
#creating lists of athletes that suffered any lower body injuries, acl injury, HSI
lb_injury_B <- incident_B %>%
filter(LB.Injury == 1) %>%
distinct(anon_id) %>%
pull(anon_id)
acl_injury_B <- incident_B %>%
filter(ACL == 1) %>%
distinct(anon_id) %>%
pull(anon_id)
hsi_injury_B <- incident_B %>%
filter(HSI == 1) %>%
distinct(anon_id) %>%
pull(anon_id)
#creating new columns in the nordic performance dataset that are binary indicators of the different injury focuses
performance_B_nordic['LB'] <- ifelse(performance_B_nordic$anon_id %in% lb_injury_B, 'Yes', 'No')
performance_B_nordic['ACL'] <- ifelse(performance_B_nordic$anon_id %in% acl_injury_B, 'Yes', 'No')
performance_B_nordic['HSI'] <- ifelse(performance_B_nordic$anon_id %in% hsi_injury_B, 'Yes', 'No')
#summarising the
performance_B_nordic %>%
group_by(LB) %>%
summarise(Avg.Max.Force = mean(Maximum.Force),
Avg.Imbalance = mean(Nordic.MEAN.Imbalance),
Avg.Rel.Force = mean(Relative.Maximum.Nordic.Bilateral.Mean))
#creating a boxplot displaying distribution of relative maximum bilateral mean in those who experienced lower body injury vs those that did not
ggplot(data = performance_B_nordic %>% filter(Position == 'Forward'), aes(x = Maximum.Force, y = LB)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of Maximum Force vs Lower Body Injury (All Time)',
y = 'Did Player Suffer Lower Body Injury',
x = 'Maximum Force (N)',
caption = 'Womens Basketball Forwards') +
theme_bw()

#creating new columns in the imtp dataset that are binary indicators of the different injury focuses
IMTP_B['LB'] <- ifelse(IMTP_B$anon_id %in% lb_injury_B, 'Yes', 'No')
IMTP_B['ACL'] <- ifelse(IMTP_B$anon_id %in% acl_injury_B, 'Yes', 'No')
IMTP_B['HSI'] <- ifelse(IMTP_B$anon_id %in% hsi_injury_B, 'Yes', 'No')
#creating a boxplot displaying distribution of relative maximum bilateral mean in those who experienced lower body injury vs those that did not
ggplot(data = IMTP_B, aes(x = Peak.Vertical.Force..Asym...N., fill = LB)) +
geom_density(alpha = 0.5) +
scale_fill_manual(values = c('#CFB87C', 'black')) +
labs(title = 'Distribution of Absolute Impulse at 200 ms vs Lower Body Injury (All Time)',
y = 'Density',
x = 'Absolute Impulse at 200 ms (Ns)',
fill = 'Lower Body Injury',
caption = 'Womens Basketball') +
theme_bw()

#creating new columns in the hj dataset that are binary indicators of the different injury focuses
HJ_B['LB'] <- ifelse(HJ_B$anon_id %in% lb_injury_B, 'Yes', 'No')
HJ_B['ACL'] <- ifelse(HJ_B$anon_id %in% acl_injury_B, 'Yes', 'No')
HJ_B['HSI'] <- ifelse(HJ_B$anon_id %in% hsi_injury_B, 'Yes', 'No')
#creating a boxplot displaying distribution of relative maximum bilateral mean in those who experienced lower body injury vs those that did not
ggplot(data = all_hopjump_incident, aes(x = Max.Jump.Height..cm., fill = LB.Injury)) +
geom_density(alpha = 0.5) +
scale_fill_manual(values = c('#CFB87C', 'black')) +
labs(title = 'Distribution of Contact Time vs Lower Body Injury (All Time)',
y = 'Density',
x = 'Best Contact Time (ms)',
fill = 'Lower Body Injury',
caption = 'All Womens Sports') +
theme_bw()

2. Soccer
#creating lists of athletes that suffered any lower body injuries, acl injury, HSI
lb_injury_S <- incident_S %>%
filter(LB.Injury == 1) %>%
distinct(anon_id) %>%
pull(anon_id)
acl_injury_S <- incident_S %>%
filter(ACL == 1) %>%
distinct(anon_id) %>%
pull(anon_id)
hsi_injury_S <- incident_S %>%
filter(HSI == 1) %>%
distinct(anon_id) %>%
pull(anon_id)
#creating new columns in the nordic performance dataset that are binary indicators of the different injury focuses
performance_S_nordic['LB'] <- ifelse(performance_S_nordic$anon_id %in% lb_injury_S, 'Yes', 'No')
performance_S_nordic['ACL'] <- ifelse(performance_S_nordic$anon_id %in% acl_injury_S, 'Yes', 'No')
performance_S_nordic['HSI'] <- ifelse(performance_S_nordic$anon_id %in% hsi_injury_S, 'Yes', 'No')
#creating a boxplot displaying distribution of relative maximum bilateral mean in those who experienced lower body injury vs those that did not
ggplot(performance_S_nordic, aes(x = Relative.Maximum.Nordic.Bilateral.Mean, y = LB)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of Maximum Relative Bilateral Force vs Lower Body Injury',
y = 'Was the Player Injured',
x = 'Maximum Relative Bilateral Force (N / kg)') +
theme_bw()

3. Lacrosse
#creating lists of athletes that suffered any lower body injuries, acl injury, HSI
lb_injury_L <- incident_L %>%
filter(LB.Injury == 1) %>%
distinct(anon_id) %>%
pull(anon_id)
acl_injury_L <- incident_L %>%
filter(ACL == 1) %>%
distinct(anon_id) %>%
pull(anon_id)
hsi_injury_L <- incident_L %>%
filter(HSI == 1) %>%
distinct(anon_id) %>%
pull(anon_id)
#creating new columns in the nordic performance dataset that are binary indicators of the different injury focuses
performance_L_nordic['LB'] <- ifelse(performance_L_nordic$anon_id %in% lb_injury_L, 'Yes', 'No')
performance_L_nordic['ACL'] <- ifelse(performance_L_nordic$anon_id %in% acl_injury_L, 'Yes', 'No')
performance_L_nordic['HSI'] <- ifelse(performance_L_nordic$anon_id %in% hsi_injury_L, 'Yes', 'No')
#creating a boxplot displaying distribution of relative maximum bilateral mean in those who experienced lower body injury vs those that did not
ggplot(performance_L_nordic, aes(x = Relative.Maximum.Nordic.Bilateral.Mean, y = LB)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of Maximum Relative Bilateral Force vs Lower Body Injury',
y = 'Was the Player Injured',
x = 'Maximum Relative Bilateral Force (N / kg)') +
theme_bw()

4. Volleyball
#creating lists of athletes that suffered any lower body injuries, acl injury, HSI
lb_injury_V <- incident_V %>%
filter(LB.Injury == 1) %>%
distinct(anon_id) %>%
pull(anon_id)
acl_injury_V <- incident_V %>%
filter(ACL == 1) %>%
distinct(anon_id) %>%
pull(anon_id)
hsi_injury_V <- incident_V %>%
filter(HSI == 1) %>%
distinct(anon_id) %>%
pull(anon_id)
#creating new columns in the nordic performance dataset that are binary indicators of the different injury focuses
performance_V_nordic['LB'] <- ifelse(performance_V_nordic$anon_id %in% lb_injury_V, 'Yes', 'No')
performance_V_nordic['ACL'] <- ifelse(performance_V_nordic$anon_id %in% acl_injury_V, 'Yes', 'No')
performance_V_nordic['HSI'] <- ifelse(performance_V_nordic$anon_id %in% hsi_injury_V, 'Yes', 'No')
#creating a boxplot displaying distribution of relative maximum bilateral mean in those who experienced lower body injury vs those that did not
ggplot(performance_V_nordic, aes(x = Relative.Maximum.Nordic.Bilateral.Mean, y = LB)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of Maximum Relative Bilateral Force vs Lower Body Injury',
y = 'Was the Player Injured',
x = 'Maximum Relative Bilateral Force (N / kg)') +
theme_bw()

In Relation to Injury Timelines
Looking 6 months in the past may be way too long need to figure out
what window works best depending on which injuries. Also want to discuss
if want to group by player and group and condense observations or just
leave observations as is.
1. Basketball
#selects variables of interest, filters for lower body injuries, and gets rid of duplicate observations
incid_b <- Incident_B %>%
filter(Body.Part %in% lower_body) %>%
dplyr::select("anon_id", "Position", "Date.of.Injury...Onset.of.symptoms", "Side", "Body.Part", "Tissue.Type", "Pathology.Type", "OSICS14.Code", "OSICS10.Code", "OSICS10.Diagnosis", "Final.Diagnosis", "Recurrence.of.Injury", "Injury.Prognosis", "General.Mechanism", "Specific.Mechanism", "FinalDiagnosisIncidentDate", "Total.Time.Injured", "Season.", "End.Date", "Start.of.Status") %>%
mutate(Start.of.Status = as.Date(Start.of.Status, format = '%m/%d/%Y'),
End.Date = as.Date(End.Date, format = '%m/%d/%Y'),
Time = as.numeric(End.Date - Start.of.Status)) %>%
group_by(anon_id, Date.of.Injury...Onset.of.symptoms) %>%
mutate(Total.Time.Injured = sum(Total.Time.Injured, na.rm = TRUE),
Total.Time = sum(Time, na.rm = TRUE),
Season. = ifelse(Season. == 'Pre-Season' | Season. == 'Summer Workouts' | Season. == 'Post-Season', 'Off-Season', Season.),
Date = as.Date(Date.of.Injury...Onset.of.symptoms, format = '%m/%d/%Y')) %>%
ungroup() %>%
dplyr::select(-c('End.Date', 'Start.of.Status', 'Time')) %>%
group_by(across(everything())) %>%
summarise(.groups = 'drop')
#creates a dataset from the incident report that separates out all the dates for lower body injuries to classify observations based on their relation to lower body injuries: within 3 months prior to first injury, between first and second injury, ect.
last_injury_B <- incid_b %>%
arrange(Date) %>%
group_by(anon_id) %>%
summarize(Dates.Final = paste0(Date, collapse = " and "),
Mechanism = paste0(General.Mechanism, collapse = " and "),
Injury = paste0(Final.Diagnosis, collapse = " and "),
Area = paste0(Body.Part, collapse = " and "),
Time.Injured = paste0(Total.Time.Injured, collapse = " and ")) %>%
separate(Dates.Final, c('Injury.1', 'Injury.2', 'Injury.3', 'Injury.4'), sep = ' and ') %>%
mutate(Injury.1.Start = as.Date(Injury.1) - months(3),
Injury.2.Start = ifelse(is.na(Injury.2), NA, Injury.1),
Injury.3.Start = ifelse(is.na(Injury.3), NA, Injury.2),
Injury.4.Start = ifelse(is.na(Injury.4), NA, Injury.3)) %>%
separate(Mechanism, c('Injury.1.Mech', 'Injury.2.Mech', 'Injury.3.Mech', 'Injury.4.Mech'), sep = ' and ') %>%
separate(Injury, c('Injury.1.Diagnosis', 'Injury.2.Diagnosis', 'Injury.3.Diagnosis', 'Injury.4.Diagnosis'), sep = ' and ') %>%
separate(Time.Injured, c('Injury.1.Time', 'Injury.2.Time', 'Injury.3.Time', 'Injury.4.Time'), sep = ' and ') %>%
separate(Area, c('Injury.1.Area', 'Injury.2.Area', 'Injury.3.Area', 'Injury.4.Area'), sep = ' and ')
Performance Data
Nordic Data
#merges the last_injury_B to the performance_B_nordic by anon_id
merge_performance_B <- merge(last_injury_B, performance_B_nordic, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_performance_B <- merge_performance_B %>%
mutate(Trend = ifelse(Trend == 'Neutral', 0, ifelse(Trend == 'Up', 1, -1)),
Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_performance_B <- merge_performance_B %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Athlete.Bodyweight..kg., Maximum.Force, Average.Force, Impulse, Nordic.Left.MEAN, Nordic.Right.MEAN, Nordic.MEAN.Imbalance, Nordic.Left.MAX, Nordic.Right.MAX, Nordic.MAX.Imbalance, Trend, Nordic...Difference.from.First.Test, Maximum.Nordic.Bilateral.Mean, Relative.Maximum.Nordic.Bilateral.Mean, Position, Sport, Injury, Area, Was.Injured, Force.Diff.Norm, Imbalance.Diff.Norm)
Hip Data
#merges the last_injury_B to the performance_B_nordic by anon_id
merge_hip_B <- merge(last_injury_B, performance_B_hip, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_hip_B <- merge_hip_B %>%
mutate(Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_hip_B <- merge_hip_B %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Athlete.Bodyweight..kg., Maximum.Force, Average.Force, Impulse, Hip.Abd.Left.MEAN, Hip.Abd.Right.MEAN, Hip.Abduction.MEAN.Imbalance, Hip.Abd.Left.MAX, Hip.Abd.Right.MAX, Hip.Abduction.MAX.Imbalance, Hip.Add.Left.MEAN, Hip.Add.Right.MEAN, Hip.Adduction.MEAN.Imbalance, Hip.Add.Left.MAX, Hip.Add.Right.MAX, Hip.Adduction.MAX.Imbalance, Bilateral.Hip.Abduction.Adduction.Ratio, Position, Sport, Injury, Area, Was.Injured)
Nordbord Data
CMJ Data
#merges the last_injury_B to the HJ_B by anon_id
merge_cmj_B <- merge(last_injury_B, b, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_cmj_B <- merge_cmj_B %>%
mutate(Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_cmj_B <- merge_cmj_B %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Countermovement.Depth..cm., Peak.Power...BM..W.kg., Landing.RFD..N.s., Eccentric.Concentric.Mean.Force.Ratio, Peak.Landing.Force..Asym...N., Peak.Power..W., Concentric.RFD..N.s., Eccentric.Mean.Braking.Force..N., Concentric.Time.to.Peak.Force..s., Landing.Net.Peak.Force...BM..N.kg., Peak.Net.Takeoff.Force...BM..N.kg., Concentric.RPD...BM..W.s.kg., Force.at.Peak.Power..N., Eccentric.Mean.Deceleration.Force..N., Eccentric.Peak.Force..N., RSI.Modified..m.s., CMJ.Stiffness..Left...N.m., CMJ.Stiffness..Right...N.m., Eccentric.Asymmetry, Concentric.Asymmetry, Peak.Landing.Asymmetry, Injury, Area, Was.Injured, Sport, DSI, DSI.Bucket)
HJ Data
#merges the last_injury_B to the HJ_B by anon_id
merge_hj_B <- merge(last_injury_B, HJ_B, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_hj_B <- merge_hj_B %>%
mutate(Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_hj_B <- merge_hj_B %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Corrected.Standing.Weight..Kg., Mean.RSI..Flight.Contact.Time., Active.Stiffness..N.m., Best.Average.Force..N., Best.Average.Force..Asym...N., Best.Time.to.Peak.Force..ms., Best.Contact.Time..ms., Best.Flight.Time..ms., Best.Impulse..N.s., Best.Peak.Force..N., Best.Peak.Force..Asym...N., Mean.Average.Force..N., Mean.Average.Force..Asym...N., Mean.Landing.RFD..N.s., Mean.Landing.RFD..Asym...N.s., Stiffness.Fatigue...., Stiffness.Fatigue..Asym....., Max.Jump.Height..cm., Injury, Area, Was.Injured, Sport, HJ.RSI, Mean.Flight.Time..ms., Mean.Contact.Time..ms.)
Need to check code, only finding 4 observations in the 3 months prior
to an injury and only one player. Of the 17 unique players who suffered
lower body injury in basketball players only 8 are represented in the HJ
dataset. All injuries with exception of ID_40 occur at least 265 days
after the observation; not very helpful.
IMTP Data
#merges the last_injury_B to the HJ_B by anon_id
merge_imtp_B <- merge(last_injury_B, IMTP_B, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_imtp_B <- merge_imtp_B %>%
mutate(Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_imtp_B <- merge_imtp_B %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Baseline.Force..N., Baseline.Force..Asym...N., Peak.Vertical.Force..N., Peak.Vertical.Force...BM..N.kg., Peak.Vertical.Force..Asym...N., RFD...50ms..N.s., RFD...50ms..Asym...N.s., RFD...100ms..N.s., RFD...100ms..Asym...N.s., RFD...150ms..N.s., RFD...150ms..Asym...N.s., RFD...200ms..N.s., RFD...200ms..Asym...N.s., Net.Peak.Vertical.Force..N.s., Net.Peak.Vertical.Force..Asym...N.s., Force.at.200ms...BM..N.kg., Injury, Area, Was.Injured, Sport)
Of the 17 unique players to suffer lower body injury, only 7 are
represented in IMTP data. All observations occur at least 99 days prior
to injury with only 11 within 180 days.
2. Soccer
#selects variables of interest, filters for lower body injuries, and gets rid of duplicate observations
incid_s <- Incident_S %>%
filter(Body.Part %in% lower_body) %>%
dplyr::select("anon_id", "Position", "Date.of.Injury...Onset.of.symptoms", "Side", "Body.Part", "Tissue.Type", "Pathology.Type", "OSICS14.Code", "OSICS10.Code", "OSICS10.Diagnosis", "Final.Diagnosis", "Recurrence.of.Injury", "Injury.Prognosis", "General.Mechanism", "Specific.Mechanism", "FinalDiagnosisIncidentDate", "Total.Time.Injured", "Season.") %>%
group_by(anon_id, Date.of.Injury...Onset.of.symptoms) %>%
mutate(Total.Time.Injured = sum(Total.Time.Injured, na.rm = TRUE),
Date = as.Date(Date.of.Injury...Onset.of.symptoms, format = '%m/%d/%Y'),
Season. = ifelse(Season. == 'Pre-Season' | Season. == 'Summer Workouts' | Season. == 'Post-Season', 'Off-Season', Season.)) %>%
ungroup() %>%
group_by(across(everything())) %>%
summarise(.groups = 'drop')
#creates a dataset from the incident report that separates out all the dates for lower body injuries to classify observations based on their relation to lower body injuries: within 3 months prior to first injury, between first and second injury, ect.
last_injury_S <- incid_s %>%
arrange(Date) %>%
group_by(anon_id) %>%
summarize(Dates.Final = paste0(Date, collapse = " and "),
Mechanism = paste0(General.Mechanism, collapse = " and "),
Injury = paste0(Final.Diagnosis, collapse = " and "),
Area = paste0(Body.Part, collapse = " and "),
Time.Injured = paste0(Total.Time.Injured, collapse = " and ")) %>%
separate(Dates.Final, c('Injury.1', 'Injury.2', 'Injury.3', 'Injury.4', 'Injury.5', 'Injury.6', 'Injury.7'), sep = ' and ') %>%
mutate(Injury.1.Start = as.Date(Injury.1) - months(3),
Injury.2.Start = ifelse(is.na(Injury.2), NA, Injury.1),
Injury.3.Start = ifelse(is.na(Injury.3), NA, Injury.2),
Injury.4.Start = ifelse(is.na(Injury.4), NA, Injury.3),
Injury.5.Start = ifelse(is.na(Injury.4), NA, Injury.4),
Injury.6.Start = ifelse(is.na(Injury.4), NA, Injury.5),
Injury.7.Start = ifelse(is.na(Injury.4), NA, Injury.6)) %>%
separate(Mechanism, c('Injury.1.Mech', 'Injury.2.Mech', 'Injury.3.Mech', 'Injury.4.Mech', 'Injury.5.Mech', 'Injury.6.Mech', 'Injury.7.Mech'), sep = ' and ') %>%
separate(Injury, c('Injury.1.Diagnosis', 'Injury.2.Diagnosis', 'Injury.3.Diagnosis', 'Injury.4.Diagnosis', 'Injury.5.Diagnosis', 'Injury.6.Diagnosis', 'Injury.7.Diagnosis'), sep = ' and ') %>%
separate(Time.Injured, c('Injury.1.Time', 'Injury.2.Time', 'Injury.3.Time', 'Injury.4.Time', 'Injury.5.Time', 'Injury.6.Time', 'Injury.7.Time'), sep = ' and ') %>%
separate(Area, c('Injury.1.Area', 'Injury.2.Area', 'Injury.3.Area', 'Injury.4.Area', 'Injury.5.Area', 'Injury.6.Area', 'Injury.7.Area'), sep = ' and ')
Performance Data
Nordic Data
#merges the last_injury_S to the performance_S_nordic by anon_id
merge_performance_S <- merge(last_injury_S, performance_S_nordic, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_performance_S <- merge_performance_S %>%
mutate(Trend = ifelse(Trend == 'Neutral', 0, ifelse(Trend == 'Up', 1, -1)),
Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
!is.na(Injury.5) & Date >= Injury.5.Start & Date <= Injury.5 ~ '5',
!is.na(Injury.6) & Date >= Injury.6.Start & Date <= Injury.6 ~ '6',
!is.na(Injury.7) & Date >= Injury.7.Start & Date <= Injury.7 ~ '7',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_performance_S <- merge_performance_S %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
Group == 5 ~ Injury.5.Diagnosis,
Group == 6 ~ Injury.6.Diagnosis,
Group == 7 ~ Injury.7.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
Group == 5 ~ Injury.5.Area,
Group == 6 ~ Injury.6.Area,
Group == 7 ~ Injury.7.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3 | Group == 4 | Group == 5 | Group == 6 | Group == 7, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Athlete.Bodyweight..kg., Maximum.Force, Average.Force, Impulse, Nordic.Left.MEAN, Nordic.Right.MEAN, Nordic.MEAN.Imbalance, Nordic.Left.MAX, Nordic.Right.MAX, Nordic.MAX.Imbalance, Trend, Nordic...Difference.from.First.Test, Maximum.Nordic.Bilateral.Mean, Relative.Maximum.Nordic.Bilateral.Mean, Position, Sport, Injury, Area, Was.Injured, Force.Diff.Norm, Imbalance.Diff.Norm)
Hip Data
#merges the last_injury_S to the performance_S_nordic by anon_id
merge_hip_S <- merge(last_injury_S, performance_S_hip, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_hip_S <- merge_hip_S %>%
mutate(Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
!is.na(Injury.5) & Date >= Injury.5.Start & Date <= Injury.5 ~ '5',
!is.na(Injury.6) & Date >= Injury.6.Start & Date <= Injury.6 ~ '6',
!is.na(Injury.7) & Date >= Injury.7.Start & Date <= Injury.7 ~ '7',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_hip_S <- merge_hip_S %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
Group == 5 ~ Injury.5.Diagnosis,
Group == 6 ~ Injury.6.Diagnosis,
Group == 7 ~ Injury.7.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
Group == 5 ~ Injury.5.Area,
Group == 6 ~ Injury.6.Area,
Group == 7 ~ Injury.7.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3 | Group == 4 | Group == 5 | Group == 6 | Group == 7, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Athlete.Bodyweight..kg., Maximum.Force, Average.Force, Impulse, Hip.Abd.Left.MEAN, Hip.Abd.Right.MEAN, Hip.Abduction.MEAN.Imbalance, Hip.Abd.Left.MAX, Hip.Abd.Right.MAX, Hip.Abduction.MAX.Imbalance, Hip.Add.Left.MEAN, Hip.Add.Right.MEAN, Hip.Adduction.MEAN.Imbalance, Hip.Add.Left.MAX, Hip.Add.Right.MAX, Hip.Adduction.MAX.Imbalance, Bilateral.Hip.Abduction.Adduction.Ratio, Position, Sport, Injury, Area, Was.Injured)
Nordbord Data
CMJ Data
#merges the last_injury_B to the HJ_B by anon_id
merge_cmj_S <- merge(last_injury_S, s, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_cmj_S <- merge_cmj_S %>%
mutate(Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
!is.na(Injury.5) & Date >= Injury.5.Start & Date <= Injury.5 ~ '5',
!is.na(Injury.6) & Date >= Injury.6.Start & Date <= Injury.6 ~ '6',
!is.na(Injury.7) & Date >= Injury.7.Start & Date <= Injury.7 ~ '7',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_cmj_S <- merge_cmj_S %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
Group == 5 ~ Injury.5.Diagnosis,
Group == 6 ~ Injury.6.Diagnosis,
Group == 7 ~ Injury.7.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
Group == 5 ~ Injury.5.Area,
Group == 6 ~ Injury.6.Area,
Group == 7 ~ Injury.7.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3 | Group == 4 | Group == 5 | Group == 6 | Group == 7, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Countermovement.Depth..cm., Peak.Power...BM..W.kg., Landing.RFD..N.s., Eccentric.Concentric.Mean.Force.Ratio, Peak.Landing.Force..Asym...N., Peak.Power..W., Concentric.RFD..N.s., Eccentric.Mean.Braking.Force..N., Concentric.Time.to.Peak.Force..s., Landing.Net.Peak.Force...BM..N.kg., Peak.Net.Takeoff.Force...BM..N.kg., Concentric.RPD...BM..W.s.kg., Force.at.Peak.Power..N., Eccentric.Mean.Deceleration.Force..N., Eccentric.Peak.Force..N., RSI.Modified..m.s., CMJ.Stiffness..Left...N.m., CMJ.Stiffness..Right...N.m., Eccentric.Asymmetry, Concentric.Asymmetry, Peak.Landing.Asymmetry, Injury, Area, Was.Injured, Sport, DSI, DSI.Bucket)
HJ Data
#merges the last_injury_B to the HJ_B by anon_id
merge_hj_S <- merge(last_injury_S, HJ_S, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_hj_S <- merge_hj_S %>%
mutate(Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
!is.na(Injury.5) & Date >= Injury.5.Start & Date <= Injury.5 ~ '5',
!is.na(Injury.6) & Date >= Injury.6.Start & Date <= Injury.6 ~ '6',
!is.na(Injury.7) & Date >= Injury.7.Start & Date <= Injury.7 ~ '7',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_hj_S <- merge_hj_S %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
Group == 5 ~ Injury.5.Diagnosis,
Group == 6 ~ Injury.6.Diagnosis,
Group == 7 ~ Injury.7.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
Group == 5 ~ Injury.5.Area,
Group == 6 ~ Injury.6.Area,
Group == 7 ~ Injury.7.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3 | Group == 4 | Group == 5 | Group == 6 | Group == 7, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Corrected.Standing.Weight..Kg., Mean.RSI..Flight.Contact.Time., Active.Stiffness..N.m., Best.Average.Force..N., Best.Average.Force..Asym...N., Best.Time.to.Peak.Force..ms., Best.Contact.Time..ms., Best.Flight.Time..ms., Best.Impulse..N.s., Best.Peak.Force..N., Best.Peak.Force..Asym...N., Mean.Average.Force..N., Mean.Average.Force..Asym...N., Mean.Landing.RFD..N.s., Mean.Landing.RFD..Asym...N.s., Stiffness.Fatigue...., Stiffness.Fatigue..Asym....., Max.Jump.Height..cm., Injury, Area, Was.Injured, Sport, HJ.RSI, Mean.Flight.Time..ms., Mean.Contact.Time..ms.)
IMTP Data
#merges the last_injury_B to the HJ_B by anon_id
merge_imtp_S <- merge(last_injury_S, IMTP_S, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_imtp_S <- merge_imtp_S %>%
mutate(Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
!is.na(Injury.5) & Date >= Injury.5.Start & Date <= Injury.5 ~ '5',
!is.na(Injury.6) & Date >= Injury.6.Start & Date <= Injury.6 ~ '6',
!is.na(Injury.7) & Date >= Injury.7.Start & Date <= Injury.7 ~ '7',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_imtp_S <- merge_imtp_S %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
Group == 5 ~ Injury.5.Diagnosis,
Group == 6 ~ Injury.6.Diagnosis,
Group == 7 ~ Injury.7.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
Group == 5 ~ Injury.5.Area,
Group == 6 ~ Injury.6.Area,
Group == 7 ~ Injury.7.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3 | Group == 4 | Group == 5 | Group == 6 | Group == 7, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Baseline.Force..N., Baseline.Force..Asym...N., Peak.Vertical.Force..N., Peak.Vertical.Force...BM..N.kg., Peak.Vertical.Force..Asym...N., RFD...50ms..N.s., RFD...50ms..Asym...N.s., RFD...100ms..N.s., RFD...100ms..Asym...N.s., RFD...150ms..N.s., RFD...150ms..Asym...N.s., RFD...200ms..N.s., RFD...200ms..Asym...N.s., Net.Peak.Vertical.Force..N.s., Net.Peak.Vertical.Force..Asym...N.s., Force.at.200ms...BM..N.kg., Injury, Area, Was.Injured, Sport)
3. Lacrosse
#selects variables of interest, filters for lower body injuries, and gets rid of duplicate observations
incid_l <- Incident_L %>%
filter(Body.Part %in% lower_body) %>%
dplyr::select("anon_id", "Position", "Date.of.Injury...Onset.of.symptoms", "Side", "Body.Part", "Tissue.Type", "Pathology.Type", "OSICS14.Code", "OSICS10.Code", "OSICS10.Diagnosis", "Final.Diagnosis", "Recurrence.of.Injury", "Injury.Prognosis", "General.Mechanism", "Specific.Mechanism", "FinalDiagnosisIncidentDate", "Total.Time.Injured", "Season.") %>%
group_by(anon_id, Date.of.Injury...Onset.of.symptoms) %>%
mutate(Total.Time.Injured = sum(Total.Time.Injured, na.rm = TRUE),
Date = as.Date(Date.of.Injury...Onset.of.symptoms, format = '%m/%d/%Y'),
Season. = ifelse(Season. == 'Pre-Season' | Season. == 'Summer Workouts' | Season. == 'Post-Season', 'Off-Season', Season.)) %>%
ungroup() %>%
group_by(across(everything())) %>%
summarise(.groups = 'drop')
#creates a dataset from the incident report that separates out all the dates for lower body injuries to classify observations based on their relation to lower body injuries: within 3 months prior to first injury, between first and second injury, ect.
last_injury_L <- incid_l %>%
arrange(Date) %>%
group_by(anon_id) %>%
summarize(Dates.Final = paste0(Date, collapse = " and "),
Mechanism = paste0(General.Mechanism, collapse = " and "),
Injury = paste0(Final.Diagnosis, collapse = " and "),
Area = paste0(Body.Part, collapse = " and "),
Time.Injured = paste0(Total.Time.Injured, collapse = " and ")) %>%
separate(Dates.Final, c('Injury.1', 'Injury.2', 'Injury.3', 'Injury.4', 'Injury.5', 'Injury.6', 'Injury.7'), sep = ' and ') %>%
mutate(Injury.1.Start = as.Date(Injury.1) - months(3),
Injury.2.Start = ifelse(is.na(Injury.2), NA, Injury.1),
Injury.3.Start = ifelse(is.na(Injury.3), NA, Injury.2),
Injury.4.Start = ifelse(is.na(Injury.4), NA, Injury.3),
Injury.5.Start = ifelse(is.na(Injury.4), NA, Injury.4),
Injury.6.Start = ifelse(is.na(Injury.4), NA, Injury.5),
Injury.7.Start = ifelse(is.na(Injury.4), NA, Injury.6)) %>%
separate(Mechanism, c('Injury.1.Mech', 'Injury.2.Mech', 'Injury.3.Mech', 'Injury.4.Mech', 'Injury.5.Mech', 'Injury.6.Mech', 'Injury.7.Mech'), sep = ' and ') %>%
separate(Injury, c('Injury.1.Diagnosis', 'Injury.2.Diagnosis', 'Injury.3.Diagnosis', 'Injury.4.Diagnosis', 'Injury.5.Diagnosis', 'Injury.6.Diagnosis', 'Injury.7.Diagnosis'), sep = ' and ') %>%
separate(Time.Injured, c('Injury.1.Time', 'Injury.2.Time', 'Injury.3.Time', 'Injury.4.Time', 'Injury.5.Time', 'Injury.6.Time', 'Injury.7.Time'), sep = ' and ') %>%
separate(Area, c('Injury.1.Area', 'Injury.2.Area', 'Injury.3.Area', 'Injury.4.Area', 'Injury.5.Area', 'Injury.6.Area', 'Injury.7.Area'), sep = ' and ')
Performance Data
Nordic Data
#merges the last_injury_S to the performance_S_nordic by anon_id
merge_performance_L <- merge(last_injury_L, performance_L_nordic, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_performance_L <- merge_performance_L %>%
mutate(Trend = ifelse(Trend == 'Neutral', 0, ifelse(Trend == 'Up', 1, -1)),
Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
!is.na(Injury.5) & Date >= Injury.5.Start & Date <= Injury.5 ~ '5',
!is.na(Injury.6) & Date >= Injury.6.Start & Date <= Injury.6 ~ '6',
!is.na(Injury.7) & Date >= Injury.7.Start & Date <= Injury.7 ~ '7',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_performance_L <- merge_performance_L %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
Group == 5 ~ Injury.5.Diagnosis,
Group == 6 ~ Injury.6.Diagnosis,
Group == 7 ~ Injury.7.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
Group == 5 ~ Injury.5.Area,
Group == 6 ~ Injury.6.Area,
Group == 7 ~ Injury.7.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3 | Group == 4 | Group == 5 | Group == 6 | Group == 7, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Athlete.Bodyweight..kg., Maximum.Force, Average.Force, Impulse, Nordic.Left.MEAN, Nordic.Right.MEAN, Nordic.MEAN.Imbalance, Nordic.Left.MAX, Nordic.Right.MAX, Nordic.MAX.Imbalance, Trend, Nordic...Difference.from.First.Test, Maximum.Nordic.Bilateral.Mean, Relative.Maximum.Nordic.Bilateral.Mean, Position, Sport, Injury, Area, Was.Injured, Force.Diff.Norm, Imbalance.Diff.Norm)
Hip Data
#merges the last_injury_L to the performance_L_nordic by anon_id
merge_hip_L <- merge(last_injury_L, performance_L_hip, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_hip_L <- merge_hip_L %>%
mutate(Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
!is.na(Injury.5) & Date >= Injury.5.Start & Date <= Injury.5 ~ '5',
!is.na(Injury.6) & Date >= Injury.6.Start & Date <= Injury.6 ~ '6',
!is.na(Injury.7) & Date >= Injury.7.Start & Date <= Injury.7 ~ '7',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_hip_L <- merge_hip_L %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
Group == 5 ~ Injury.5.Diagnosis,
Group == 6 ~ Injury.6.Diagnosis,
Group == 7 ~ Injury.7.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
Group == 5 ~ Injury.5.Area,
Group == 6 ~ Injury.6.Area,
Group == 7 ~ Injury.7.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3 | Group == 4 | Group == 5 | Group == 6 | Group == 7, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Athlete.Bodyweight..kg., Maximum.Force, Average.Force, Impulse, Hip.Abd.Left.MEAN, Hip.Abd.Right.MEAN, Hip.Abduction.MEAN.Imbalance, Hip.Abd.Left.MAX, Hip.Abd.Right.MAX, Hip.Abduction.MAX.Imbalance, Hip.Add.Left.MEAN, Hip.Add.Right.MEAN, Hip.Adduction.MEAN.Imbalance, Hip.Add.Left.MAX, Hip.Add.Right.MAX, Hip.Adduction.MAX.Imbalance, Bilateral.Hip.Abduction.Adduction.Ratio, Position, Sport, Injury, Area, Was.Injured)
Nordbord Data
CMJ Data
#merges the last_injury_B to the HJ_B by anon_id
merge_cmj_L <- merge(last_injury_L, l, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_cmj_L <- merge_cmj_L %>%
mutate(Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
!is.na(Injury.5) & Date >= Injury.5.Start & Date <= Injury.5 ~ '5',
!is.na(Injury.6) & Date >= Injury.6.Start & Date <= Injury.6 ~ '6',
!is.na(Injury.7) & Date >= Injury.7.Start & Date <= Injury.7 ~ '7',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_cmj_L <- merge_cmj_L %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
Group == 5 ~ Injury.5.Diagnosis,
Group == 6 ~ Injury.6.Diagnosis,
Group == 7 ~ Injury.7.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
Group == 5 ~ Injury.5.Area,
Group == 6 ~ Injury.6.Area,
Group == 7 ~ Injury.7.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3 | Group == 4 | Group == 5 | Group == 6 | Group == 7, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Countermovement.Depth..cm., Peak.Power...BM..W.kg., Landing.RFD..N.s., Eccentric.Concentric.Mean.Force.Ratio, Peak.Landing.Force..Asym...N., Peak.Power..W., Concentric.RFD..N.s., Eccentric.Mean.Braking.Force..N., Concentric.Time.to.Peak.Force..s., Landing.Net.Peak.Force...BM..N.kg., Peak.Net.Takeoff.Force...BM..N.kg., Concentric.RPD...BM..W.s.kg., Force.at.Peak.Power..N., Eccentric.Mean.Deceleration.Force..N., Eccentric.Peak.Force..N., RSI.Modified..m.s., CMJ.Stiffness..Left...N.m., CMJ.Stiffness..Right...N.m., Eccentric.Asymmetry, Concentric.Asymmetry, Peak.Landing.Asymmetry, Injury, Area, Was.Injured, Sport, DSI, DSI.Bucket)
HJ Data
#merges the last_injury_B to the HJ_B by anon_id
merge_hj_L <- merge(last_injury_L, HJ_L, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_hj_L <- merge_hj_L %>%
mutate(Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
!is.na(Injury.5) & Date >= Injury.5.Start & Date <= Injury.5 ~ '5',
!is.na(Injury.6) & Date >= Injury.6.Start & Date <= Injury.6 ~ '6',
!is.na(Injury.7) & Date >= Injury.7.Start & Date <= Injury.7 ~ '7',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_hj_L <- merge_hj_L %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
Group == 5 ~ Injury.5.Diagnosis,
Group == 6 ~ Injury.6.Diagnosis,
Group == 7 ~ Injury.7.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
Group == 5 ~ Injury.5.Area,
Group == 6 ~ Injury.6.Area,
Group == 7 ~ Injury.7.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3 | Group == 4 | Group == 5 | Group == 6 | Group == 7, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Corrected.Standing.Weight..Kg., Mean.RSI..Flight.Contact.Time., Active.Stiffness..N.m., Best.Average.Force..N., Best.Average.Force..Asym...N., Best.Time.to.Peak.Force..ms., Best.Contact.Time..ms., Best.Flight.Time..ms., Best.Impulse..N.s., Best.Peak.Force..N., Best.Peak.Force..Asym...N., Mean.Average.Force..N., Mean.Average.Force..Asym...N., Mean.Landing.RFD..N.s., Mean.Landing.RFD..Asym...N.s., Stiffness.Fatigue...., Stiffness.Fatigue..Asym....., Max.Jump.Height..cm., Injury, Area, Was.Injured, Sport, HJ.RSI, Mean.Flight.Time..ms., Mean.Contact.Time..ms.)
IMTP Data
#merges the last_injury_B to the HJ_B by anon_id
merge_imtp_L <- merge(last_injury_L, IMTP_L, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_imtp_L <- merge_imtp_L %>%
mutate(Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
!is.na(Injury.5) & Date >= Injury.5.Start & Date <= Injury.5 ~ '5',
!is.na(Injury.6) & Date >= Injury.6.Start & Date <= Injury.6 ~ '6',
!is.na(Injury.7) & Date >= Injury.7.Start & Date <= Injury.7 ~ '7',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_imtp_L <- merge_imtp_L %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
Group == 5 ~ Injury.5.Diagnosis,
Group == 6 ~ Injury.6.Diagnosis,
Group == 7 ~ Injury.7.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
Group == 5 ~ Injury.5.Area,
Group == 6 ~ Injury.6.Area,
Group == 7 ~ Injury.7.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3 | Group == 4 | Group == 5 | Group == 6 | Group == 7, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Baseline.Force..N., Baseline.Force..Asym...N., Peak.Vertical.Force..N., Peak.Vertical.Force...BM..N.kg., Peak.Vertical.Force..Asym...N., RFD...50ms..N.s., RFD...50ms..Asym...N.s., RFD...100ms..N.s., RFD...100ms..Asym...N.s., RFD...150ms..N.s., RFD...150ms..Asym...N.s., RFD...200ms..N.s., RFD...200ms..Asym...N.s., Net.Peak.Vertical.Force..N.s., Net.Peak.Vertical.Force..Asym...N.s., Force.at.200ms...BM..N.kg., Injury, Area, Was.Injured, Sport)
4. Volleyball
#selects variables of interest, filters for lower body injuries, and gets rid of duplicate observations
incid_v <- Incident_V %>%
filter(Body.Part %in% lower_body) %>%
dplyr::select("anon_id", "Position", "Date.of.Injury...Onset.of.symptoms", "Side", "Body.Part", "Tissue.Type", "Pathology.Type", "OSICS14.Code", "OSICS10.Code", "OSICS10.Diagnosis", "Final.Diagnosis", "Recurrence.of.Injury", "Injury.Prognosis", "General.Mechanism", "Specific.Mechanism", "FinalDiagnosisIncidentDate", "Total.Time.Injured", "Season.") %>%
group_by(anon_id, Date.of.Injury...Onset.of.symptoms) %>%
mutate(Total.Time.Injured = sum(Total.Time.Injured, na.rm = TRUE),
Date = as.Date(Date.of.Injury...Onset.of.symptoms, format = '%m/%d/%Y'),
Season. = ifelse(Season. == 'Pre-Season' | Season. == 'Summer Workouts' | Season. == 'Post-Season', 'Off-Season', Season.)) %>%
ungroup() %>%
group_by(across(everything())) %>%
summarise(.groups = 'drop')
#creates a dataset from the incident report that separates out all the dates for lower body injuries to classify observations based on their relation to lower body injuries: within 3 months prior to first injury, between first and second injury, ect.
last_injury_V <- incid_v %>%
arrange(Date) %>%
group_by(anon_id) %>%
summarize(Dates.Final = paste0(Date, collapse = " and "),
Mechanism = paste0(General.Mechanism, collapse = " and "),
Injury = paste0(Final.Diagnosis, collapse = " and "),
Area = paste0(Body.Part, collapse = " and "),
Time.Injured = paste0(Total.Time.Injured, collapse = " and ")) %>%
separate(Dates.Final, c('Injury.1', 'Injury.2', 'Injury.3', 'Injury.4', 'Injury.5', 'Injury.6', 'Injury.7'), sep = ' and ') %>%
mutate(Injury.1.Start = as.Date(Injury.1) - months(3),
Injury.2.Start = ifelse(is.na(Injury.2), NA, Injury.1),
Injury.3.Start = ifelse(is.na(Injury.3), NA, Injury.2),
Injury.4.Start = ifelse(is.na(Injury.4), NA, Injury.3),
Injury.5.Start = ifelse(is.na(Injury.4), NA, Injury.4),
Injury.6.Start = ifelse(is.na(Injury.4), NA, Injury.5),
Injury.7.Start = ifelse(is.na(Injury.4), NA, Injury.6)) %>%
separate(Mechanism, c('Injury.1.Mech', 'Injury.2.Mech', 'Injury.3.Mech', 'Injury.4.Mech', 'Injury.5.Mech', 'Injury.6.Mech', 'Injury.7.Mech'), sep = ' and ') %>%
separate(Injury, c('Injury.1.Diagnosis', 'Injury.2.Diagnosis', 'Injury.3.Diagnosis', 'Injury.4.Diagnosis', 'Injury.5.Diagnosis', 'Injury.6.Diagnosis', 'Injury.7.Diagnosis'), sep = ' and ') %>%
separate(Time.Injured, c('Injury.1.Time', 'Injury.2.Time', 'Injury.3.Time', 'Injury.4.Time', 'Injury.5.Time', 'Injury.6.Time', 'Injury.7.Time'), sep = ' and ') %>%
separate(Area, c('Injury.1.Area', 'Injury.2.Area', 'Injury.3.Area', 'Injury.4.Area', 'Injury.5.Area', 'Injury.6.Area', 'Injury.7.Area'), sep = ' and ')
Performance Data
Nordic Data
#merges the last_injury_S to the performance_S_nordic by anon_id
merge_performance_V <- merge(last_injury_V, performance_V_nordic, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_performance_V <- merge_performance_V %>%
mutate(Trend = ifelse(Trend == 'Neutral', 0, ifelse(Trend == 'Up', 1, -1)),
Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
!is.na(Injury.5) & Date >= Injury.5.Start & Date <= Injury.5 ~ '5',
!is.na(Injury.6) & Date >= Injury.6.Start & Date <= Injury.6 ~ '6',
!is.na(Injury.7) & Date >= Injury.7.Start & Date <= Injury.7 ~ '7',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_performance_V <- merge_performance_V %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
Group == 5 ~ Injury.5.Diagnosis,
Group == 6 ~ Injury.6.Diagnosis,
Group == 7 ~ Injury.7.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
Group == 5 ~ Injury.5.Area,
Group == 6 ~ Injury.6.Area,
Group == 7 ~ Injury.7.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3 | Group == 4 | Group == 5 | Group == 6 | Group == 7, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Athlete.Bodyweight..kg., Maximum.Force, Average.Force, Impulse, Nordic.Left.MEAN, Nordic.Right.MEAN, Nordic.MEAN.Imbalance, Nordic.Left.MAX, Nordic.Right.MAX, Nordic.MAX.Imbalance, Trend, Nordic...Difference.from.First.Test, Maximum.Nordic.Bilateral.Mean, Relative.Maximum.Nordic.Bilateral.Mean, Position, Sport, Injury, Area, Was.Injured, Force.Diff.Norm, Imbalance.Diff.Norm)
Hip Data
#merges the last_injury_V to the performance_V_nordic by anon_id
merge_hip_V <- merge(last_injury_V, performance_V_hip, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_hip_V <- merge_hip_V %>%
mutate(Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
!is.na(Injury.5) & Date >= Injury.5.Start & Date <= Injury.5 ~ '5',
!is.na(Injury.6) & Date >= Injury.6.Start & Date <= Injury.6 ~ '6',
!is.na(Injury.7) & Date >= Injury.7.Start & Date <= Injury.7 ~ '7',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_hip_V <- merge_hip_V %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
Group == 5 ~ Injury.5.Diagnosis,
Group == 6 ~ Injury.6.Diagnosis,
Group == 7 ~ Injury.7.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
Group == 5 ~ Injury.5.Area,
Group == 6 ~ Injury.6.Area,
Group == 7 ~ Injury.7.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3 | Group == 4 | Group == 5 | Group == 6 | Group == 7, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Athlete.Bodyweight..kg., Maximum.Force, Average.Force, Impulse, Hip.Abd.Left.MEAN, Hip.Abd.Right.MEAN, Hip.Abduction.MEAN.Imbalance, Hip.Abd.Left.MAX, Hip.Abd.Right.MAX, Hip.Abduction.MAX.Imbalance, Hip.Add.Left.MEAN, Hip.Add.Right.MEAN, Hip.Adduction.MEAN.Imbalance, Hip.Add.Left.MAX, Hip.Add.Right.MAX, Hip.Adduction.MAX.Imbalance, Bilateral.Hip.Abduction.Adduction.Ratio, Position, Sport, Injury, Area, Was.Injured)
Nordbord Data
CMJ Data
#merges the last_injury_B to the HJ_B by anon_id
merge_cmj_V <- merge(last_injury_V, v, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_cmj_V <- merge_cmj_V %>%
mutate(Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
!is.na(Injury.5) & Date >= Injury.5.Start & Date <= Injury.5 ~ '5',
!is.na(Injury.6) & Date >= Injury.6.Start & Date <= Injury.6 ~ '6',
!is.na(Injury.7) & Date >= Injury.7.Start & Date <= Injury.7 ~ '7',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_cmj_V <- merge_cmj_V %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
Group == 5 ~ Injury.5.Diagnosis,
Group == 6 ~ Injury.6.Diagnosis,
Group == 7 ~ Injury.7.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
Group == 5 ~ Injury.5.Area,
Group == 6 ~ Injury.6.Area,
Group == 7 ~ Injury.7.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3 | Group == 4 | Group == 5 | Group == 6 | Group == 7, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Countermovement.Depth..cm., Peak.Power...BM..W.kg., Landing.RFD..N.s., Eccentric.Concentric.Mean.Force.Ratio, Peak.Landing.Force..Asym...N., Peak.Power..W., Concentric.RFD..N.s., Eccentric.Mean.Braking.Force..N., Concentric.Time.to.Peak.Force..s., Landing.Net.Peak.Force...BM..N.kg., Peak.Net.Takeoff.Force...BM..N.kg., Concentric.RPD...BM..W.s.kg., Force.at.Peak.Power..N., Eccentric.Mean.Deceleration.Force..N., Eccentric.Peak.Force..N., RSI.Modified..m.s., CMJ.Stiffness..Left...N.m., CMJ.Stiffness..Right...N.m., Eccentric.Asymmetry, Concentric.Asymmetry, Peak.Landing.Asymmetry, Injury, Area, Was.Injured, Sport, DSI, DSI.Bucket)
HJ Data
#merges the last_injury_B to the HJ_B by anon_id
merge_hj_V <- merge(last_injury_V, HJ_V, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_hj_V <- merge_hj_V %>%
mutate(Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
!is.na(Injury.5) & Date >= Injury.5.Start & Date <= Injury.5 ~ '5',
!is.na(Injury.6) & Date >= Injury.6.Start & Date <= Injury.6 ~ '6',
!is.na(Injury.7) & Date >= Injury.7.Start & Date <= Injury.7 ~ '7',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_hj_V <- merge_hj_V %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
Group == 5 ~ Injury.5.Diagnosis,
Group == 6 ~ Injury.6.Diagnosis,
Group == 7 ~ Injury.7.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
Group == 5 ~ Injury.5.Area,
Group == 6 ~ Injury.6.Area,
Group == 7 ~ Injury.7.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3 | Group == 4 | Group == 5 | Group == 6 | Group == 7, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Corrected.Standing.Weight..Kg., Mean.RSI..Flight.Contact.Time., Active.Stiffness..N.m., Best.Average.Force..N., Best.Average.Force..Asym...N., Best.Time.to.Peak.Force..ms., Best.Contact.Time..ms., Best.Flight.Time..ms., Best.Impulse..N.s., Best.Peak.Force..N., Best.Peak.Force..Asym...N., Mean.Average.Force..N., Mean.Average.Force..Asym...N., Mean.Landing.RFD..N.s., Mean.Landing.RFD..Asym...N.s., Stiffness.Fatigue...., Stiffness.Fatigue..Asym....., Max.Jump.Height..cm., Injury, Area, Was.Injured, Sport, HJ.RSI, Mean.Flight.Time..ms., Mean.Contact.Time..ms.)
IMTP Data
#merges the last_injury_B to the HJ_B by anon_id
merge_imtp_V <- merge(last_injury_V, IMTP_V, by = c('anon_id'), all = TRUE)
#creates a variable called Group that groups based on date within injury intervals and outputs 'After' if the date is after all injuries, and then these are omitted
merge_imtp_V <- merge_imtp_V %>%
mutate(Group = case_when(
is.na(Injury.1) | Date < Injury.1.Start ~ '0',
!is.na(Injury.1) & Date >= Injury.1.Start & Date <= Injury.1 ~ '1',
!is.na(Injury.2) & Date >= Injury.2.Start & Date <= Injury.2 ~ '2',
!is.na(Injury.3) & Date >= Injury.3.Start & Date <= Injury.3 ~ '3',
!is.na(Injury.4) & Date >= Injury.4.Start & Date <= Injury.4 ~ '4',
!is.na(Injury.5) & Date >= Injury.5.Start & Date <= Injury.5 ~ '5',
!is.na(Injury.6) & Date >= Injury.6.Start & Date <= Injury.6 ~ '6',
!is.na(Injury.7) & Date >= Injury.7.Start & Date <= Injury.7 ~ '7',
TRUE ~ 'After')) %>%
filter(Group != 'After')
#condenses observations based on group and player summarizing means of variables of interest
merge_imtp_V <- merge_imtp_V %>%
mutate(Injury = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Diagnosis,
Group == 2 ~ Injury.2.Diagnosis,
Group == 3 ~ Injury.3.Diagnosis,
Group == 4 ~ Injury.4.Diagnosis,
Group == 5 ~ Injury.5.Diagnosis,
Group == 6 ~ Injury.6.Diagnosis,
Group == 7 ~ Injury.7.Diagnosis,
TRUE ~ 'After'
),
Area = case_when(
Group == 0 ~ 'None',
Group == 1 ~ Injury.1.Area,
Group == 2 ~ Injury.2.Area,
Group == 3 ~ Injury.3.Area,
Group == 4 ~ Injury.4.Area,
Group == 5 ~ Injury.5.Area,
Group == 6 ~ Injury.6.Area,
Group == 7 ~ Injury.7.Area,
TRUE ~ 'After'
)) %>%
mutate(Was.Injured = ifelse(Group == 1 | Group == 2 | Group == 3 | Group == 4 | Group == 5 | Group == 6 | Group == 7, 'Yes', Group)) %>%
dplyr::select(anon_id, Date, Baseline.Force..N., Baseline.Force..Asym...N., Peak.Vertical.Force..N., Peak.Vertical.Force...BM..N.kg., Peak.Vertical.Force..Asym...N., RFD...50ms..N.s., RFD...50ms..Asym...N.s., RFD...100ms..N.s., RFD...100ms..Asym...N.s., RFD...150ms..N.s., RFD...150ms..Asym...N.s., RFD...200ms..N.s., RFD...200ms..Asym...N.s., Net.Peak.Vertical.Force..N.s., Net.Peak.Vertical.Force..Asym...N.s., Force.at.200ms...BM..N.kg., Injury, Area, Was.Injured, Sport)
Merging All Performance Data Together
Nordic Data
#creating a dataset containing performance data accross all sports
performance_all_injury <- rbind(merge_performance_B, merge_performance_S, merge_performance_L, merge_performance_V) %>%
mutate(Thresh = ifelse(Relative.Maximum.Nordic.Bilateral.Mean >= 5, 'Yes', 'No'),
Sport.2 = ifelse(Sport == 'Basketball' | Sport == 'Volleyball', 'Court', 'Field'))
Hip Data
#creating a dataset containing performance data accross all sports
hip_all_injury <- rbind(merge_hip_B, merge_hip_S, merge_hip_L, merge_hip_V) %>%
mutate(Avg.Abd.Mean = (Hip.Abd.Left.MEAN + Hip.Abd.Right.MEAN) / 2,
Avg.Add.Mean = (Hip.Add.Left.MEAN + Hip.Add.Right.MEAN) / 2,
Avg.Abd.Max = (Hip.Abd.Left.MAX + Hip.Abd.Right.MAX) / 2,
Avg.Add.Max = (Hip.Add.Left.MAX + Hip.Add.Right.MAX) / 2,
Relative.Abd.Mean = Avg.Abd.Mean / Athlete.Bodyweight..kg.,
Relative.Add.Mean = Avg.Add.Mean / Athlete.Bodyweight..kg.,
Relative.Abd.Max = Avg.Abd.Max / Athlete.Bodyweight..kg.,
Relative.Add.Max = Avg.Add.Max / Athlete.Bodyweight..kg.,
Sport.2 = ifelse(Sport == 'Basketball' | Sport == 'Volleyball', 'Court', 'Field'))
HJ Data
#creating a dataset containing performance data accross all sports
hj_all_injury <- rbind(merge_hj_B, merge_hj_S, merge_hj_L, merge_hj_V) %>%
mutate(Sport.2 = ifelse(Sport == 'Basketball' | Sport == 'Volleyball', 'Court', 'Field'),
Was.Injured = ifelse(Was.Injured == 'Yes', 'Yes', 'No'),
Ankle = ifelse(Area == 'Ankle', 'Yes', 'No'),
Knee = ifelse(Area == 'Knee', 'Yes', 'No'))
field_ankle <- hj_all_injury %>%
filter(Sport.2 == 'Field' & Area %in% c('Ankle', 'None')) %>%
mutate(Was.Injured. = as.factor(ifelse(Was.Injured == 'Yes', 1, 0)))
ggplot(data = field_ankle, aes(Max.Jump.Height..cm., fill = Was.Injured)) +
geom_density(alpha = 0.5) +
scale_fill_manual(values = c('#CFB87C', '#000000')) +
geom_vline(xintercept = 21.5725, color = 'red', linetype = 'dashed') +
labs(title = 'Max Jump Height vs Ankle Injury',
x = 'Max Jump Height (cm)',
y = 'Density',
fill = 'Ankle Injury',
caption = 'CU Womens Soccer and Lacrosse') +
scale_x_continuous(breaks = seq(0, 50, 4)) +
theme_bw()

roc_obj <- roc(response = field_ankle$Was.Injured, predictor = field_ankle$Max.Jump.Height..cm., direction = ">")
plot(roc_obj, print.auc = TRUE, col = "#CFB87C", main = "ROC Curve for Training Load")
roc_coords <- coords(roc_obj, x = "best", best.method = "youden", ret = c("threshold", "sensitivity", "specificity"))
print(roc_coords)
model <- glm(Was.Injured. ~ Mean.Contact.Time..ms., data = field_ankle, family = 'binomial')
summary(model)
#Q2:What trends in strength do we see across the women’s team sports?
a. Soccer, lacrosse, volleyball, basketball.
#reload datasets
Incident_B <- read.csv("~/T2P2-data-analysis-2025/data-sets/Incident Report WBB.csv")
Incident_S <- read.csv("~/T2P2-data-analysis-2025/data-sets/Incident Report WSOC.csv")
Incident_L <- read.csv("~/T2P2-data-analysis-2025/data-sets/Incident Report WLAX.csv")
Incident_V <- read.csv("~/T2P2-data-analysis-2025/data-sets/Incident Report WVB.csv")
# count # of what type of injuries in each sport
count_categories <- function(data, column_name) {
data |>
dplyr::count(.data[[column_name]]) |>
dplyr::arrange(desc(n))
}
Incident_B <- Incident_B %>%
filter(Body.Part. %in% c("Thigh", "Ankle", "Lower leg", "Knee", "Foot", "Groin/hip"))
Incident_S <- Incident_S %>%
filter(Body.Part. %in% c("Thigh", "Ankle", "Lower leg", "Knee", "Foot", "Groin/hip"))
Incident_V <- Incident_V %>%
filter(Body.Part. %in% c("Thigh", "Ankle", "Lower leg", "Knee", "Foot", "Groin/hip"))
Incident_L <- Incident_L %>%
filter(Body.Part. %in% c("Thigh", "Ankle", "Lower leg", "Knee", "Foot", "Groin/hip"))
#convert to character
Incident_B$Body.Part. <- as.character(Incident_B$Body.Part.)
Incident_S$Body.Part. <- as.character(Incident_S$Body.Part.)
Incident_V$Body.Part. <- as.character(Incident_V$Body.Part.)
Incident_L$Body.Part. <- as.character(Incident_L$Body.Part.)
count_categories(Incident_B, "Body.Part.")
count_categories(Incident_S, "Body.Part.")
count_categories(Incident_V, "Body.Part.")
count_categories(Incident_L, "Body.Part.")
#count of all different test types by sport
count_categories(Forcedecks_B, "Test.Type")
count_categories(Forcedecks_S, "Test.Type")
count_categories(Forcedecks_V, "Test.Type")
count_categories(Forcedecks_L, "Test.Type")
##Forcedecks
#make a categorical variable including each injury to plot together
#1= LB.Injury, 2=HSI, 3=ACL
all_incident$InjuryType <- with(all_incident,
ifelse(ACL == 1, "ACL",
ifelse(HSI == 1, "HSI",
ifelse(LB.Injury == 1, "Lower body", NA))))
#convert to factor
all_incident$InjuryType <- factor(all_incident$InjuryType, levels = c("Lower body", "HSI", "ACL"))
#now in data only keep those 3 injuries
all_incid <- all_incident[all_incident$Body.Part. %in% c("Thigh", "Ankle", "Lower leg", "Knee", "Foot", "Groin/hip"),]
#plot count on y axis, then x= each sport , fill each injury
ggplot(data=all_incid, aes(x=Sport, fill=InjuryType))+
geom_bar(na.rm=TRUE) +
scale_fill_manual(values=c("Lower body"='#CFB87C',
"HSI"='white',
"ACL"='black')) +
labs(title="The Number of Each Injury by Sport",
y="Count",
x="Sport",
fill="Injury Type") +
theme_minimal()

#recurrence of injury plot
ggplot(all_incid, aes(x=Sport, fill=Recurrence.of.Injury))+
geom_bar(na.rm=TRUE) +
scale_fill_manual(values=c("New Injury/Illness"='#CFB87C',
"First recurrence"='black',
"Multiple recurrence"='white',
"Pre-existing injury/illness"= 'grey')) +
labs(title="The Number of Each Injury Recurrence by Sport",
y="Count",
x="Sport",
fill="Recurrence") +
theme_minimal()

#DSI bucket plot
ggplot(all_IMTP_incident, aes(x=Sport, fill=DSI.Bucket))+
geom_bar(na.rm=TRUE) +
scale_fill_manual(values=c("Maximal Strength Training"='black',
"Concurrent Training"='white',
"Ballistic Strength Training"='#CFB87C')) +
labs(title="The Number of Each DSI Bucket by Sport",
y="Count",
x="Sport",
fill="DSI Bucket") +
theme_minimal()

As seen in the past project with the football data, the main type of
injury is a new injury, which makes it much harder to prevent or
predict. Across all of the womens sports their focus is on ballistic
strength training which emphasizes speed and explosiveness.
#Each Sports Individual Athletes Injuries Over time
#filter lacrosse incident data for plots
injury_l_cumulative <- incident_l %>%
filter(Status=="Out") %>%
arrange(anon_id, Start.of.Status) %>%
group_by(anon_id) %>%
mutate(CumulativeInjuries = row_number())
#line graph
ggplot(injury_l_cumulative,aes(x =CumulativeInjuries ,y = Start.of.Status,color = as.factor(anon_id))) +
geom_line() +
labs(x = "Cumulative Injuries per Athlete", y = "Injury Time Period", color = "Athlete ID") +
#xlim(0,5)+
scale_x_continuous(breaks=c(0,1,2,3,4,5))+
theme_minimal()

ggplot(injury_l_cumulative,aes(x =Start.of.Status ,y = CumulativeInjuries,color = as.factor(anon_id))) +
geom_line() +
labs(x = "Injury Time Period", y = "Cumulative Injuries per Athlete", color = "Athlete ID") +
# ylim(0,5)+
scale_y_continuous(breaks=c(0,1,2,3,4,5))+
theme_minimal()

#figure out how to get it to start at 0 and show other lines
#bar plot
ggplot(injury_l_cumulative, aes(x = Start.of.Status, y = CumulativeInjuries, group = anon_id)) +
geom_segment(aes(xend = End.Date, yend = CumulativeInjuries, color = anon_id), size = 2) +
geom_point(aes(color = anon_id)) +
scale_y_continuous(breaks=c(0,1,2,3,4,5))+
labs(x = "Injury Time Period", y = "Cumulative Injuries per Athlete") +
theme_minimal()
Warning: Removed 5 rows containing missing values or values outside the scale range
(`geom_segment()`).

#filter basketball incident data for plots
injury_b_cumulative <- incident_b %>%
filter(Status=="Out") %>%
arrange(anon_id, Start.of.Status) %>%
group_by(anon_id) %>%
mutate(CumulativeInjuries = row_number())
#line graph
ggplot(injury_b_cumulative,aes(x =CumulativeInjuries ,y = Start.of.Status,color = as.factor(anon_id))) +
geom_line() +
labs(x = "Cumulative Injuries per Athlete", y = "Injury Time Period", color = "Athlete ID") +
scale_x_continuous(breaks=c(0,1,2,3,4,5))+
#xlim(0,5)+
theme_minimal()

ggplot(injury_b_cumulative,aes(x =Start.of.Status ,y = CumulativeInjuries,color = as.factor(anon_id))) +
geom_line() +
labs(x = "Injury Time Period", y = "Cumulative Injuries per Athlete", color = "Athlete ID") +
scale_y_continuous(breaks=c(0,1,2,3,4,5))+
#ylim(0,5)+
theme_minimal()

#figure out how to get it to start at 0 and show other lines
#bar plot
ggplot(injury_b_cumulative, aes(x = Start.of.Status, y = CumulativeInjuries, group = anon_id)) +
geom_segment(aes(xend = End.Date, yend = CumulativeInjuries, color = anon_id), size = 2) +
geom_point(aes(color = anon_id)) +
scale_y_continuous(breaks=c(0,1,2,3,4,5))+
labs(x = "Injury Time Period", y = "Cumulative Injuries per Athlete") +
theme_minimal()
Warning: Removed 1 row containing missing values or values outside the scale range
(`geom_segment()`).

#filter soccer incident data for plots
injury_s_cumulative <- incident_s %>%
filter(Status=="Out") %>%
arrange(anon_id, Start.of.Status) %>%
group_by(anon_id) %>%
mutate(CumulativeInjuries = row_number())
#line graph
ggplot(injury_s_cumulative,aes(x =CumulativeInjuries ,y = Start.of.Status,color = as.factor(anon_id))) +
geom_line() +
labs(x = "Cumulative Injuries per Athlete", y = "Injury Time Period", color = "Athlete ID") +
scale_x_continuous(breaks=c(0,1,2,3,4))+
#xlim(0,5)+
theme_minimal()

ggplot(injury_s_cumulative,aes(x =Start.of.Status ,y = CumulativeInjuries,color = as.factor(anon_id))) +
geom_line() +
labs(x = "Injury Time Period", y = "Cumulative Injuries per Athlete", color = "Athlete ID") +
scale_y_continuous(breaks=c(0,1,2,3,4))+
#ylim(0,5)+
theme_minimal()

#figure out how to get it to start at 0 and show other lines
#bar plot
ggplot(injury_s_cumulative, aes(x = Start.of.Status, y = CumulativeInjuries, group = anon_id)) +
geom_segment(aes(xend = End.Date, yend = CumulativeInjuries, color = anon_id), size = 2) +
geom_point(aes(color = anon_id)) +
scale_y_continuous(breaks=c(0,1,2,3,4))+
labs(x = "Injury Time Period", y = "Cumulative Injuries per Athlete") +
theme_minimal()
Warning: Removed 2 rows containing missing values or values outside the scale range
(`geom_segment()`).

#filter volleyball incident data for plots
injury_v_cumulative <- incident_v %>%
filter(Status=="Out") %>%
arrange(anon_id, Start.of.Status) %>%
group_by(anon_id) %>%
mutate(CumulativeInjuries = row_number())
#line graph
ggplot(injury_v_cumulative,aes(x =CumulativeInjuries ,y = Start.of.Status,color = as.factor(anon_id))) +
geom_line() +
labs(x = "Cumulative Injuries per Athlete", y = "Injury Time Period", color = "Athlete ID") +
scale_x_continuous(breaks=c(0,1,2,3))+
#xlim(0,5)+
theme_minimal()

ggplot(injury_v_cumulative,aes(x =Start.of.Status ,y = CumulativeInjuries,color = as.factor(anon_id))) +
geom_line() +
labs(x = "Injury Time Period", y = "Cumulative Injuries per Athlete", color = "Athlete ID") +
scale_y_continuous(breaks=c(0,1,2,3))+
# ylim(0,5)+
theme_minimal()

#figure out how to get it to start at 0 and show other lines
#bar plot
ggplot(injury_v_cumulative, aes(x = Start.of.Status, y = CumulativeInjuries, group = anon_id)) +
geom_segment(aes(xend = End.Date, yend = CumulativeInjuries, color = anon_id), size = 2) +
geom_point(aes(color = anon_id)) +
scale_y_continuous(breaks=c(0,1,2,3))+
labs(x = "Injury Time Period", y = "Cumulative Injuries per Athlete") +
theme_minimal()

#Forcedecks Strength Trends Sport to Sport 1. CMJ + Incident
all_CMJ_incident <- all_CMJ_incident %>%
mutate(Thresh = ifelse(Relative.Concentric.Power.Bilateral >= 0.5, 'Yes', 'No'))
#table with lower body injury on left and whether the observation is above/below threshold
table(all_CMJ_incident$LB.Injury, all_CMJ_incident$Thresh)
No Yes
0 2 888
1 31 2550
#boxplot
ggplot(all_CMJ_incident, aes(x = Relative.Concentric.Power.Bilateral, y = Sport)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of Relative Concentric Bilateral Power Across Sports',
y = 'Sport',
x = 'Relative Concentric Bilateral Power') +
theme_bw()

#density plot
ggplot(all_CMJ_incident, aes(x = Eccentric.Concentric.Mean.Force.Ratio, fill = Sport)) +
geom_density(alpha = 0.4) +
scale_fill_manual(values = c('#CFB87C', '#666666', '#000000', '#8C7853')) +
scale_color_manual(values = c('#CFB87C', '#666666', '#000000', '#8C7853')) +
labs(title = 'Distribution of Eccentric Concentric Mean Force Ratio Across Sports',
x = 'Eccentric Concentric Mean Force Ratio',
y = 'Density') +
theme_bw()

#anova test for differences
anova_result <- aov(Eccentric.Concentric.Mean.Force.Ratio ~ Sport, data = all_CMJ_incident)
summary(anova_result)
Df Sum Sq Mean Sq F value Pr(>F)
Sport 3 1932 644.1 23.51 4.69e-15 ***
Residuals 3389 92866 27.4
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
78 observations deleted due to missingness
all_CMJ_incident <- all_CMJ_incident %>%
mutate(Thresh0 = ifelse(Max.Jump.Height..cm. >= 0.5, 'Yes', 'No'))
#table with lower body injury on left and whether the observation is above/below threshold
table(all_CMJ_incident$LB.Injury, all_CMJ_incident$Thresh0)
Yes
0 890
1 2581
#boxplot
ggplot(all_CMJ_incident, aes(x = Max.Jump.Height..cm., y = Sport)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of Maximum Jump Height Across Sports',
y = 'Sport',
x = 'Maximum Jump Height (cm)') +
theme_bw()

#density plot
ggplot(all_CMJ_incident, aes(x = Max.Jump.Height..cm., fill = Sport)) +
geom_density(alpha = 0.4) +
scale_fill_manual(values = c('#CFB87C', '#666666', '#000000', '#8C7853')) +
scale_color_manual(values = c('#CFB87C', '#666666', '#000000', '#8C7853')) +
labs(title = 'Distribution of Maximum Jump Height (cm) Across Sports',
x = 'Maximum Jump Height (cm)',
y = 'Density') +
theme_bw()

#anova test for differences
anova_result <- aov(Max.Jump.Height..cm. ~ Sport, data = all_CMJ_incident)
summary(anova_result)
Df Sum Sq Mean Sq F value Pr(>F)
Sport 3 3465 1155.1 38.79 <2e-16 ***
Residuals 3389 100907 29.8
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
78 observations deleted due to missingness
all_CMJ_incident <- all_CMJ_incident %>%
mutate(Thresh1 = ifelse(Concentric.Maximum.RFD..N.s. >= 0.5, 'Yes', 'No'))
#table w/ lower body injury on left and whether the observation is above/below threshold
table(all_CMJ_incident$LB.Injury, all_CMJ_incident$Thresh1)
Yes
0 890
1 2581
#boxplot
ggplot(all_CMJ_incident, aes(x = Concentric.Maximum.RFD..N.s., y = Sport)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of the Maximum Concentric RFD Across Sports',
y = 'Sport',
x = 'Maximum Concentric RFD (N/s)') +
theme_bw()

#density plot
ggplot(all_CMJ_incident, aes(x = Concentric.Maximum.RFD..N.s., fill = Sport)) +
geom_density(alpha = 0.4) +
scale_fill_manual(values = c('#CFB87C', '#666666', '#000000', '#8C7853')) +
scale_color_manual(values = c('#CFB87C', '#666666', '#000000', '#8C7853')) +
labs(title = 'Distribution of Maximum Concentric RFD (N/s) Across Sports',
x = 'Maximum Concentric RFD (N/s)',
y = 'Density') +
theme_bw()

#anova test for differences
anova_result <- aov(Concentric.Maximum.RFD..N.s. ~ Sport, data = all_CMJ_incident)
summary(anova_result)
Df Sum Sq Mean Sq F value Pr(>F)
Sport 3 2.906e+08 96863751 23.93 2.52e-15 ***
Residuals 3389 1.371e+10 4046879
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
78 observations deleted due to missingness
all_CMJ_incident <- all_CMJ_incident %>%
mutate(Thresh2 = ifelse(Eccentric.Mean.Braking.Force..N. >= 0.5, 'Yes', 'No'))
#table with lower body injury on left and whether the observation is above/below threshold
table(all_CMJ_incident$LB.Injury, all_CMJ_incident$Thresh2)
Yes
0 890
1 2581
#boxplot
ggplot(all_CMJ_incident, aes(x = Eccentric.Mean.Braking.Force..N., y = Sport)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of the Mean Eccentric Braking Force Across Sports',
y = 'Sport',
x = 'Mean Eccentric Braking Force (N)') +
theme_bw()

all_CMJ_incident <- all_CMJ_incident %>%
mutate(Thresh3 = ifelse(Max.RSI.Modified.VALD>= 0.5, 'Yes', 'No'))
#table with lower body injury on left and whether the observation is above/below threshold
table(all_CMJ_incident$LB.Injury, all_CMJ_incident$Thresh3)
No Yes
0 619 271
1 1901 680
#boxplot
ggplot(all_CMJ_incident, aes(x = Max.RSI.Modified.VALD, y = Sport)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of the Maximum RSI from VALD Across Sports',
y = 'Sport',
x = 'Maximum RSI from VALD') +
theme_bw()

- Hop Jump + Incident
all_hopjump_incident <- all_hopjump_incident %>%
mutate(Thresh = ifelse(Max.Jump.Height..cm. >= 0.5, 'Yes', 'No'))
#table w/ lower body injury on left and whether the observation is above/below threshold
table(all_hopjump_incident$LB.Injury, all_hopjump_incident$Thresh)
Yes
0 1121
1 4476
#boxplot
ggplot(all_hopjump_incident, aes(x = Max.Jump.Height..cm., y = Sport)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of the Maximum Jump Height (cm) Across Sports',
y = 'Sport',
x = 'Maximum Jump Height (cm)') +
theme_bw()

#density plot
ggplot(all_hopjump_incident, aes(x = Max.Jump.Height..cm., fill = Sport)) +
geom_density(alpha = 0.4) +
scale_fill_manual(values = c('#CFB87C', '#666666', '#000000', '#8C7853')) +
scale_color_manual(values = c('#CFB87C', '#666666', '#000000', '#8C7853')) +
labs(title = 'Distribution of Maximum Jump Height (cm) Across Sports',
x = 'Maximum Jump Height (cm)',
y = 'Density') +
theme_bw()

#anova test for differences
anova_result <- aov(Max.Jump.Height..cm. ~ Sport, data = all_hopjump_incident)
summary(anova_result)
Df Sum Sq Mean Sq F value Pr(>F)
Sport 3 2299 766.5 15.96 2.49e-10 ***
Residuals 5484 263356 48.0
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
109 observations deleted due to missingness
all_hopjump_incident <- all_hopjump_incident %>%
mutate(Thresh1 = ifelse(Mean.RSI..Flight.Contact.Time. >= 0.5, 'Yes', 'No'))
#table w/ lower body injury on left and whether the observation is above/below threshold
table(all_hopjump_incident$LB.Injury, all_hopjump_incident$Thresh1)
Yes
0 1121
1 4476
#boxplot
ggplot(all_hopjump_incident, aes(x = Mean.RSI..Flight.Contact.Time., y = Sport)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of the Average RSI Flight Contact Time Across Sports',
y = 'Sport',
x = 'Average RSI Flight Contact Time') +
theme_bw()

#density plot
ggplot(all_hopjump_incident, aes(x = Mean.RSI..Flight.Contact.Time., fill = Sport)) +
geom_density(alpha = 0.4) +
scale_fill_manual(values = c('#CFB87C', 'white', 'black','yellow')) +
labs(title = 'Distribution of Average RSI Flight Contact Time Across Sports',
x = 'Average RSI Flight Contact Time',
y = 'Density') +
theme_bw()

#anova test for differences
anova_result <- aov(Mean.RSI..Flight.Contact.Time. ~ Sport, data = all_hopjump_incident)
summary(anova_result)
Df Sum Sq Mean Sq F value Pr(>F)
Sport 3 32.7 10.886 46.2 <2e-16 ***
Residuals 5484 1292.0 0.236
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
109 observations deleted due to missingness
all_hopjump_incident <- all_hopjump_incident %>%
mutate(Thresh2 = ifelse(Best.Contact.Time..ms. >= 0.5, 'Yes', 'No'))
#table w/ lower body injury on left and whether the observation is above/below threshold
table(all_hopjump_incident$LB.Injury, all_hopjump_incident$Thresh2)
No Yes
0 1114 7
1 4462 14
#boxplot
ggplot(all_hopjump_incident, aes(x = Best.Contact.Time..ms., y = Sport)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of the Best Contact Time (m/s) Across Sports',
y = 'Sport',
x = 'Best Contact Time (m/s)') +
theme_bw()

#density plot
ggplot(all_hopjump_incident, aes(x = Best.Contact.Time..ms., fill = Sport)) +
geom_density(alpha = 0.4) +
scale_fill_manual(values = c('#CFB87C', 'white', 'black','yellow')) +
labs(title = 'Distribution of the Best Contact Time (m/s) Across Sports',
x = 'Best Contact Time (m/s)',
y = 'Density') +
theme_bw()

#anova test for differences
anova_result <- aov(Best.Contact.Time..ms. ~ Sport, data = all_hopjump_incident)
summary(anova_result)
Df Sum Sq Mean Sq F value Pr(>F)
Sport 3 0.345 0.11491 36.98 <2e-16 ***
Residuals 5484 17.043 0.00311
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
109 observations deleted due to missingness
- Isometric Mid Thigh Pull (IMTP) + Incident
#could use this or Peak.Vertical.Force..N. or Net.Peak.Vertical.Force..N.s.
all_IMTP_incident <- all_IMTP_incident %>%
mutate(Thresh = ifelse(Peak.Vertical.Force...BM..N.kg. >= 0.5, 'Yes', 'No'))
#table w/ lower body injury on left and whether the observation is above/below threshold
table(all_IMTP_incident$LB.Injury, all_IMTP_incident$Thresh)
Yes
0 308
1 1244
#boxplot
ggplot(all_IMTP_incident, aes(x = Peak.Vertical.Force...BM..N.kg., y = Sport)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of the Peak Vertical Force Across Sports',
y = 'Sport',
x = 'Peak Vertical Force (BM N/kg)') +
theme_bw()

#density plot
ggplot(all_IMTP_incident, aes(x = Peak.Vertical.Force...BM..N.kg., fill = Sport)) +
geom_density(alpha = 0.4) +
scale_fill_manual(values = c('#CFB87C', 'white', 'black','yellow')) +
labs(title = 'Distribution of the Peak Vertical Force Across Sports',
x = 'Peak Vertical Force (BM N/kg)',
y = 'Density') +
theme_bw()

#anova test for differences
anova_result <- aov(Peak.Vertical.Force...BM..N.kg. ~ Sport, data = all_IMTP_incident)
summary(anova_result)
Df Sum Sq Mean Sq F value Pr(>F)
Sport 3 44591 14864 38.37 <2e-16 ***
Residuals 1524 590338 387
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
24 observations deleted due to missingness
all_IMTP_incident <- all_IMTP_incident %>%
mutate(Thresh1 = ifelse(RFD...200ms..N.s. >= 0.5, 'Yes', 'No'))
#table w/ lower body injury on left and whether the observation is above/below threshold
table(all_IMTP_incident$LB.Injury, all_IMTP_incident$Thresh1)
Yes
0 308
1 1244
#boxplot
ggplot(all_IMTP_incident, aes(x = RFD...200ms..N.s., y = Sport)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of the Rate of Force Development at 200ms Across Sports',
y = 'Sport',
x = 'Rate of Force Development at 200ms (N/s)') +
theme_bw()

#density plot
ggplot(all_IMTP_incident, aes(x = RFD...200ms..N.s., fill = Sport)) +
geom_density(alpha = 0.4) +
scale_fill_manual(values = c('#CFB87C', 'white', 'black','yellow')) +
labs(title = 'Distribution of the Rate of Force Development at 200ms Across Sports',
x = 'Rate of Force Development at 200ms (N/s)',
y = 'Density') +
theme_bw()

#anova test for differences
anova_result <- aov(RFD...200ms..N.s. ~ Sport, data = all_IMTP_incident)
summary(anova_result)
Df Sum Sq Mean Sq F value Pr(>F)
Sport 3 1.967e+08 65581185 14.8 1.67e-09 ***
Residuals 1524 6.751e+09 4429745
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
24 observations deleted due to missingness
all_IMTP_incident <- all_IMTP_incident %>%
mutate(Thresh2 = ifelse(Force.at.200ms...BM..N.kg. >= 0.5, 'Yes', 'No'))
#table w/ lower body injury on left and whether the observation is above/below threshold
table(all_IMTP_incident$LB.Injury, all_IMTP_incident$Thresh2)
Yes
0 308
1 1244
#boxplot
ggplot(all_IMTP_incident, aes(x = Force.at.200ms...BM..N.kg., y = Sport)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of the Force at 200ms Across Sports',
y = 'Sport',
x = 'Force at 200ms BM (N/kg)') +
theme_bw()

#density plot
ggplot(all_IMTP_incident, aes(x = Force.at.200ms...BM..N.kg., fill = Sport)) +
geom_density(alpha = 0.4) +
scale_fill_manual(values = c('#CFB87C', 'white', 'black','yellow')) +
labs(title = 'Distribution of the Force at 200ms Across Sports',
x = 'Force at 200ms BM (N/kg)',
y = 'Density') +
theme_bw()

#anova test for differences
anova_result <- aov(Force.at.200ms...BM..N.kg. ~ Sport, data = all_IMTP_incident)
summary(anova_result)
Df Sum Sq Mean Sq F value Pr(>F)
Sport 3 4387 1462.4 20.71 3.73e-13 ***
Residuals 1524 107596 70.6
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
24 observations deleted due to missingness
- Single Leg Jump + Incident
all_SLJ_incident <- all_SLJ_incident %>%
mutate(Thresh = ifelse(Max.Jump.Height..cm. >= 0.5, 'Yes', 'No'))
#table w/ lower body injury on left and whether the observation is above/below threshold
table(all_SLJ_incident$LB.Injury, all_SLJ_incident$Thresh)
Yes
0 72
1 389
#boxplot
ggplot(all_SLJ_incident, aes(x = Max.Jump.Height..cm., y = Sport)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of the Maximum Jump Height Across Sports',
y = 'Sport',
x = 'Maximum Jump Height (cm)') +
theme_bw()

#density plot
ggplot(all_SLJ_incident, aes(x = Max.Jump.Height..cm., fill = Sport)) +
geom_density(alpha = 0.4) +
scale_fill_manual(values = c('#CFB87C', 'white', 'black','yellow')) +
labs(title = 'Distribution of the Maximum Jump Height Across Sports',
x = 'Maximum Jump Height (cm)',
y = 'Density') +
theme_bw()

#anova test for differences
anova_result <- aov(Max.Jump.Height..cm. ~ Sport, data = all_SLJ_incident)
summary(anova_result)
Df Sum Sq Mean Sq F value Pr(>F)
Sport 3 122 40.75 3.871 0.0094 **
Residuals 446 4694 10.52
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
11 observations deleted due to missingness
#CHOOSE TO KEEP THIS ONE OR ONE DIRECTLY ABOVE
all_SLJ_incident <- all_SLJ_incident %>%
mutate(Thresh1 = ifelse(Jump.Height..Flight.Time...cm. >= 0.5, 'Yes', 'No'))
#table w/ lower body injury on left and whether the observation is above/below threshold
table(all_SLJ_incident$LB.Injury, all_SLJ_incident$Thresh1)
Yes
0 72
1 389
#boxplot
ggplot(all_SLJ_incident, aes(x = Jump.Height..Flight.Time...cm., y = Sport)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of the Jump Height Flight Time Across Sports',
y = 'Sport',
x = 'Jump Height Flight Time (cm)') +
theme_bw()

#density plot
ggplot(all_SLJ_incident, aes(x = Jump.Height..Flight.Time...cm., fill = Sport)) +
geom_density(alpha = 0.4) +
scale_fill_manual(values = c('#CFB87C', 'white', 'black','yellow')) +
labs(title = 'Distribution of the Jump Height Flight Time Across Sports',
x = 'Jump Height Flight Time (cm)',
y = 'Density') +
theme_bw()

#anova test for differences
anova_result <- aov(Jump.Height..Flight.Time...cm. ~ Sport, data = all_SLJ_incident)
summary(anova_result)
Df Sum Sq Mean Sq F value Pr(>F)
Sport 3 278 92.67 11.16 4.51e-07 ***
Residuals 446 3705 8.31
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
11 observations deleted due to missingness
all_SLJ_incident <- all_SLJ_incident %>%
mutate(Thresh2 = ifelse(Landing.RFD..N.s. >= 0.5, 'Yes', 'No'))
#table w/ lower body injury on left and whether the observation is above/below threshold
table(all_SLJ_incident$LB.Injury, all_SLJ_incident$Thresh2)
Yes
0 72
1 389
#boxplot
ggplot(all_SLJ_incident, aes(x = Landing.RFD..N.s., y = Sport)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of the Landing Rate of Force Development Across Sports',
y = 'Sport',
x= 'Landing Rate of Force Development (N/s)') +
theme_bw()

#density plot
ggplot(all_SLJ_incident, aes(x = Landing.RFD..N.s., fill = Sport)) +
geom_density(alpha = 0.4) +
scale_fill_manual(values = c('#CFB87C', 'white', 'black','yellow')) +
labs(title = 'Distribution of the Landing Rate of Force Development Across Sports',
x = 'Landing Rate of Force Development (N/s)',
y = 'Density') +
theme_bw()

#anova test for differences
anova_result <- aov(Landing.RFD..N.s. ~ Sport, data = all_SLJ_incident)
summary(anova_result)
Df Sum Sq Mean Sq F value Pr(>F)
Sport 3 8.309e+09 2.770e+09 18.52 2.44e-11 ***
Residuals 446 6.670e+10 1.496e+08
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
11 observations deleted due to missingness
all_SLJ_incident <- all_SLJ_incident %>%
mutate(Thresh2 = ifelse(Max.Concentric.Peak.Force..N. >= 0.5, 'Yes', 'No'))
#table w/ lower body injury on left and whether the observation is above/below threshold
table(all_SLJ_incident$LB.Injury, all_SLJ_incident$Thresh2)
Yes
0 72
1 389
#boxplot
ggplot(all_SLJ_incident, aes(x = Max.Concentric.Peak.Force..N., y = Sport)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of the Maximum Concentric Peak Force Across Sports',
y = 'Sport',
x= 'Maximum Concentric Peak Force (N)') +
theme_bw()

#density plot
ggplot(all_SLJ_incident, aes(x = Max.Concentric.Peak.Force..N., fill = Sport)) +
geom_density(alpha = 0.4) +
scale_fill_manual(values = c('#CFB87C', 'white', 'black','yellow')) +
labs(title = 'Distribution of the Maximum Concentric Peak Force Across Sports',
x = 'Maximum Concentric Peak Force (N)',
y = 'Density') +
theme_bw()

#anova test for differences
anova_result <- aov(Max.Concentric.Peak.Force..N. ~ Sport, data = all_SLJ_incident)
summary(anova_result)
Df Sum Sq Mean Sq F value Pr(>F)
Sport 3 1163262 387754 8.335 2.1e-05 ***
Residuals 446 20747806 46520
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
11 observations deleted due to missingness
all_SLJ_incident <- all_SLJ_incident %>%
mutate(Thresh3 = ifelse(Concentric.Impulse..Ns. >= 0.5, 'Yes', 'No'))
#table w/ lower body injury on left and whether the observation is above/below threshold
table(all_SLJ_incident$LB.Injury, all_SLJ_incident$Thresh3)
Yes
0 72
1 389
#boxplot
ggplot(all_SLJ_incident, aes(x = Max.Concentric.Peak.Force..N., y = Sport)) +
geom_boxplot(fill = '#CFB87C', color = 'black') +
labs(title = 'Distribution of the Concentric Impulse Across Sports',
y = 'Sport',
x= 'Concentric Impulse (N/s)') +
theme_bw()

#density plot
ggplot(all_SLJ_incident, aes(x = Concentric.Impulse..Ns., fill = Sport)) +
geom_density(alpha = 0.4) +
scale_fill_manual(values = c('#CFB87C', 'white', 'black','yellow')) +
labs(title = 'Distribution of the Concentric Impulse Across Sports',
x = 'Concentric Impulse (N/s)',
y = 'Density') +
theme_bw()

#anova test for differences
anova_result <- aov(Concentric.Impulse..Ns. ~ Sport, data = all_SLJ_incident)
summary(anova_result)
Df Sum Sq Mean Sq F value Pr(>F)
Sport 3 13454 4485 23.31 4.95e-14 ***
Residuals 446 85812 192
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
11 observations deleted due to missingness
Recreating Normative Data
CMJ Data
#creating a dataset containing all information for CMJ
cmj <- rbind(b, s, l, v) %>%
mutate(Sport.2 = ifelse(Sport == 'Basketball' | Sport == 'Volleyball', 'Court', 'Field')) %>%
filter(Jump.Height..Imp.Mom...cm. < 100)
#summarizes important metrics
cmj %>%
group_by(Sport) %>%
summarize(`Average Depth` = mean(Countermovement.Depth..cm.),
`Peak Power w/ BW` = mean(Peak.Power...BM..W.kg.),
`Peak Power` = mean(Peak.Power..W.),
`Ecc/Conc Force Ratio` = mean(Eccentric.Concentric.Mean.Force.Ratio),
`Ecc Braking Force` = mean(Eccentric.Mean.Braking.Force..N.),
`Conc Time to Peak` = mean(Concentric.Time.to.Peak.Force..s.),
`DSI` = mean(DSI))
This code with different variables and/or sports switched out was
used multiple times.
#creates a density plot for maximum force across sports
ggplot(cmj, aes(x = Jump.Height..Imp.Mom...cm., color = Sport, fill = Sport)) +
geom_density(alpha = 0.4) +
scale_fill_manual(values = c('#CFB87C', '#666666', '#000000', '#8C7853')) +
scale_color_manual(values = c('#CFB87C', '#666666', '#000000', '#8C7853')) +
labs(title = 'Distribution of Jump Height Across Sports',
x = 'Jump Height (cm)',
y = 'Density') +
scale_x_continuous(breaks = seq(from = 0, to = 100, by = 5)) +
theme_bw()

#creates a density plot for maximum force across sports
ggplot(cmj, aes(x = Jump.Height..Imp.Mom...cm., color = Sport.2, fill = Sport.2)) +
geom_density(alpha = 0.5) +
scale_fill_manual(values = c('#CFB87C', '#000000')) +
scale_color_manual(values = c('#CFB87C', '#000000')) +
labs(title = 'Distribution of Jump Height Across Sports',
x = 'Jump Height (cm)',
y = 'Density',
fill = 'Sport Type',
color = 'Sport Type') +
scale_x_continuous(breaks = seq(from = 0, to = 100, by = 5)) +
theme_bw()

img <- image_read("jh_wlx.png")
img_grob <- rasterGrob(img, interpolate = TRUE)
img_plot <- ggdraw() + draw_grob(img_grob, x = 0, y = 0, width = 1, height = 1)
p <- ggplot(l, aes(x = Jump.Height..Imp.Mom...cm.)) +
geom_density(fill = '#CFB87C') +
labs(title = 'Distribution of Jump Height',
x = 'Jump Height (cm)',
y = 'Density',
caption = 'CU Womens Lacrosse') +
geom_vline(xintercept = median(l$Jump.Height..Imp.Mom...cm.), linetype = 'solid') +
geom_vline(xintercept = c(quantile(l$Jump.Height..Imp.Mom...cm., probs = c(0.01, 0.25, 0.75, 0.99))), linetype = 'dashed') +
scale_x_continuous(breaks = seq(from = 0, to = 100, by = 5)) +
theme_bw()
combined <- plot_grid(p, img_plot,
rel_widths = c(1.5, 1),
nrow = 1, # <- horizontal layout
align = "h") # <- align vertically
combined

#calculates the 25th, 50th, and 75th percentile of CU data
quantile(l$Jump.Height..Imp.Mom...cm., probs = c(0.25, 0.5, 0.75))
25% 50% 75%
24.266 28.238 31.586
#performs a Welch's T-test for difference of means
t.test(Peak.Net.Takeoff.Force...BM..N.kg. ~ Sport.2, data = cmj)
Welch Two Sample t-test
data: Peak.Net.Takeoff.Force...BM..N.kg. by Sport.2
t = 6.2608, df = 1418.8, p-value = 5.064e-10
alternative hypothesis: true difference in means between group Court and group Field is not equal to 0
95 percent confidence interval:
0.526236 1.006462
sample estimates:
mean in group Court mean in group Field
13.81904 13.05269
t.test(Landing.Net.Peak.Force...BM..N.kg. ~ Sport.2, data = cmj)
Welch Two Sample t-test
data: Landing.Net.Peak.Force...BM..N.kg. by Sport.2
t = -6.9679, df = 1036.1, p-value = 5.715e-12
alternative hypothesis: true difference in means between group Court and group Field is not equal to 0
95 percent confidence interval:
-6.404498 -3.589916
sample estimates:
mean in group Court mean in group Field
32.32932 37.32653
t.test(Force.at.Peak.Power..N. ~ Sport.2, data = cmj)
Welch Two Sample t-test
data: Force.at.Peak.Power..N. by Sport.2
t = 21.548, df = 1748.6, p-value < 2.2e-16
alternative hypothesis: true difference in means between group Court and group Field is not equal to 0
95 percent confidence interval:
203.0702 243.7393
sample estimates:
mean in group Court mean in group Field
1600.664 1377.259
t.test(RSI.Modified..m.s. ~ Sport.2, data = cmj)
Welch Two Sample t-test
data: RSI.Modified..m.s. by Sport.2
t = 15.458, df = 1727.3, p-value < 2.2e-16
alternative hypothesis: true difference in means between group Court and group Field is not equal to 0
95 percent confidence interval:
0.06805981 0.08784077
sample estimates:
mean in group Court mean in group Field
0.4551350 0.3771848
t.test(DSI ~ Sport.2, data = cmj)
Welch Two Sample t-test
data: DSI by Sport.2
t = -56.953, df = 1646.8, p-value < 2.2e-16
alternative hypothesis: true difference in means between group Court and group Field is not equal to 0
95 percent confidence interval:
-0.3909848 -0.3649511
sample estimates:
mean in group Court mean in group Field
0.3757253 0.7536933
Most differences are very significant between court and field
sports.
t.test(Force.at.Peak.Power..N. ~ Sport, data = cmj %>% filter(Sport %in% c('Soccer', 'Lacrosse')))
Welch Two Sample t-test
data: Force.at.Peak.Power..N. by Sport
t = -7.6057, df = 537.33, p-value = 1.275e-13
alternative hypothesis: true difference in means between group Lacrosse and group Soccer is not equal to 0
95 percent confidence interval:
-129.53649 -76.35824
sample estimates:
mean in group Lacrosse mean in group Soccer
1317.972 1420.919
HJ Data
#creating a dataset containing all information for CMJ
hj <- rbind(HJ_B, HJ_S, HJ_L, HJ_V) %>%
mutate(Sport.2 = ifelse(Sport == 'Basketball' | Sport == 'Volleyball', 'Court', 'Field'))
#creates a density plot for maximum force across sports
ggplot(hj, aes(x = Mean.Contact.Time..ms., color = Sport, fill = Sport)) +
geom_density(alpha = 0.4) +
scale_fill_manual(values = c('#CFB87C', '#666666', '#000000', '#8C7853')) +
scale_color_manual(values = c('#CFB87C', '#666666', '#000000', '#8C7853')) +
labs(title = 'Distribution of Mean Contact Time Across Sports',
x = 'Mean Contact Time (s)',
y = 'Density') +
scale_x_continuous(breaks = seq(from = 0, to = 7, by = 0.04)) +
theme_bw()

#creates a density plot for maximum force across sports
ggplot(hj, aes(x = Mean.Contact.Time..ms., color = Sport.2, fill = Sport.2)) +
geom_density(alpha = 0.5) +
scale_fill_manual(values = c('#CFB87C', '#000000')) +
scale_color_manual(values = c('#CFB87C', '#000000')) +
labs(title = 'Distribution of Mean Contact Time Across Sports',
x = 'Mean Contact Time (s)',
y = 'Density',
fill = 'Sport Type',
color = 'Sport Type') +
scale_x_continuous(breaks = seq(from = 0, to = 7, by = 0.04)) +
theme_bw()

#reads in the image of the normative data and normalizes the size
img <- image_read("hjcontact_wlx.png")
img_grob <- rasterGrob(img, interpolate = TRUE)
img_plot <- ggdraw() + draw_grob(img_grob, x = 0, y = 0, width = 1, height = 1)
#creates a plot of the CU data named "p"
p <- ggplot(HJ_L, aes(x = Mean.Contact.Time..ms.)) +
geom_density(fill = '#CFB87C') +
labs(title = 'Distribution of Mean Contact Time',
x = 'Mean Contact Time (s)',
y = 'Density',
caption = 'CU Womens Lacrosse') +
geom_vline(xintercept = median(HJ_L$Mean.Contact.Time..ms.), linetype = 'solid') +
geom_vline(xintercept = c(quantile(HJ_L$Mean.Contact.Time..ms., probs = c(0.01, 0.25, 0.75, 0.99))), linetype = 'dashed') +
scale_x_continuous(breaks = seq(from = 0, to = 100, by = 0.04)) +
theme_bw()
#combines both the CU data density plot and puts normative image on the right
combined <- plot_grid(p, img_plot,
rel_widths = c(1.5, 1),
nrow = 1, # <- horizontal layout
align = "h") # <- align horizontally
#prints final graphic
combined

#finds 25th, 50th, and 75th percentiles of CU data
quantile(HJ_L$Mean.Contact.Time..ms., probs = c(0.25, 0.5, 0.75))
25% 50% 75%
0.192 0.222 0.296
t.test(Mean.Contact.Time..ms. ~ Sport, data = hj %>% filter(Sport %in% c('Lacrosse', 'Volleyball')))
Error in t.test.formula(Mean.Contact.Time..ms. ~ Sport, data = hj %>% :
grouping factor must have exactly 2 levels
Nordic Data
#creating a dataset containing performance data across all sports
performance_all_nordic <- rbind(performance_B_nordic, performance_S_nordic, performance_L_nordic, performance_V_nordic) %>%
mutate(Thresh = ifelse(Relative.Maximum.Nordic.Bilateral.Mean >= 5, 'Yes', 'No'),
Sport.2 = ifelse(Sport == 'Basketball' | Sport == 'Volleyball', 'Court', 'Field'))
#summarizes averages in most important variables by sport
performance_all_nordic %>%
group_by(Sport) %>%
summarise(`Average Maximum Nordic Bilateral Mean` = mean(Maximum.Nordic.Bilateral.Mean),
`Average Relative Maximum Nordic Bilateral Mean` = mean(Relative.Maximum.Nordic.Bilateral.Mean),
`Average Mean Imbalance` = mean(Nordic.MEAN.Imbalance),
`Average Max Imbalance` = mean(Nordic.MAX.Imbalance))
#creates a subset of just the court sports
field_all <- performance_all_nordic %>%
filter(Sport.2 == 'Field')
#creates a subset of just the court sports
court_all <- performance_all_nordic %>%
filter(Sport.2 == 'Court')
#creates a density plot for maximum force across sports
ggplot(performance_all_nordic, aes(x = Maximum.Nordic.Bilateral.Mean, color = Sport, fill = Sport)) +
geom_density(alpha = 0.4) +
scale_fill_manual(values = c('#CFB87C', '#666666', '#000000', '#8C7853')) +
scale_color_manual(values = c('#CFB87C', '#666666', '#000000', '#8C7853')) +
labs(title = 'Distribution of Maximum Nordic Force Across Sports',
x = 'Maximum Bilateral Average Force (N)',
y = 'Density') +
scale_x_continuous(breaks = seq(from = 0, to = 600, by = 50)) +
theme_bw()

#creates a density plot for maximum bilateral force across sport type
ggplot(performance_all_nordic, aes(x = Maximum.Nordic.Bilateral.Mean, color = Sport.2, fill = Sport.2)) +
geom_density(alpha = 0.5) +
scale_fill_manual(values = c('#CFB87C', '#000000')) +
scale_color_manual(values = c('#CFB87C', '#000000')) +
labs(title = 'Distribution of Maximum Nordic Force Across Sports',
x = 'Maximum Bilateral Average Force (N)',
y = 'Density',
fill = 'Sport Type',
color = 'Sport Type') +
scale_x_continuous(breaks = seq(from = 0, to = 600, by = 50)) +
theme_bw()

#reads in the image of the normative data and normalizes the size
img <- image_read("nordic_wlx.png")
img_grob <- rasterGrob(img, interpolate = TRUE)
img_plot <- ggdraw() + draw_grob(img_grob, x = 0, y = 0, width = 1, height = 1)
#creates a plot of the CU data named "p"
p <- ggplot(performance_L_nordic, aes(x = Maximum.Nordic.Bilateral.Mean)) +
geom_density(fill = '#CFB87C') +
labs(title = 'Distribution of Maximum Nordic Force',
x = 'Maximum Bilateral Average Force (N)',
y = 'Density',
caption = 'CU Womens Lacrosse') +
geom_vline(xintercept = median(performance_L_nordic$Maximum.Nordic.Bilateral.Mean), linetype = 'solid') +
geom_vline(xintercept = c(quantile(performance_L_nordic$Maximum.Nordic.Bilateral.Mean, probs = c(0.01, 0.25, 0.75, 0.99))), linetype = 'dashed') +
scale_x_continuous(breaks = seq(from = 0, to = 1000, by = 50)) +
theme_bw()
#combines bot the CU data density plot and puts normative image on the right
combined <- plot_grid(p, img_plot,
rel_widths = c(1.5, 1),
nrow = 1, # <- horizontal layout
align = "h") # <- align horizontally
#prints final graphic
combined
The large outliers are ID_69 in womens lacrosse and ID_3 in womens
soccer. ID_69 did not appear in the incident report at all. ID_3
appeared 3 times in the incident report with Right Knee Pain/Injury Not
otherwise specified - 05/08/2024, Left Quadriceps strain/tear -
03/06/2024, Right Gluteus medius/minimus strain - 10/02/2024. The
observation for performance strength was 02/03/2025 which indicates it
occured after all of her injuries. Both athletes also have a handful of
other observations that fit into the center of the distribution.
#finds 25th, 50th, and 75th percentiles of CU data
quantile(performance_L_nordic$Maximum.Nordic.Bilateral.Mean, probs = c(0.25, 0.5, 0.75))
#performs a Welch's T-test for difference of means
t.test(Maximum.Nordic.Bilateral.Mean ~ Sport.2, data = performance_all_nordic, alternative = 'greater')
Welch Two Sample t-test
data: Maximum.Nordic.Bilateral.Mean by Sport.2
t = 14.032, df = 1260, p-value < 2.2e-16
alternative hypothesis: true difference in means between group Court and group Field is greater than 0
95 percent confidence interval:
33.69462 Inf
sample estimates:
mean in group Court mean in group Field
331.0441 292.8717
t.test(Relative.Maximum.Nordic.Bilateral.Mean ~ Sport.2, data = performance_all_nordic, alternative = 'less')
Welch Two Sample t-test
data: Relative.Maximum.Nordic.Bilateral.Mean by Sport.2
t = -5.7354, df = 1358.9, p-value = 5.986e-09
alternative hypothesis: true difference in means between group Court and group Field is less than 0
95 percent confidence interval:
-Inf -0.137256
sample estimates:
mean in group Court mean in group Field
4.266084 4.458585
t.test(Nordic.MEAN.Imbalance ~ Sport.2, data = performance_all_nordic)
Welch Two Sample t-test
data: Nordic.MEAN.Imbalance by Sport.2
t = -2.159, df = 1678.8, p-value = 0.03099
alternative hypothesis: true difference in means between group Court and group Field is not equal to 0
95 percent confidence interval:
-1.26983119 -0.06089679
sample estimates:
mean in group Court mean in group Field
7.314286 7.979650
t.test(Impulse ~ Sport.2, data = performance_all_nordic, alternative = 'greater')
Welch Two Sample t-test
data: Impulse by Sport.2
t = 5.2717, df = 1714.1, p-value = 7.615e-08
alternative hypothesis: true difference in means between group Court and group Field is greater than 0
95 percent confidence interval:
362.0737 Inf
sample estimates:
mean in group Court mean in group Field
4201.784 3675.374
t.test(Force.Diff.Norm ~ Sport.2, data = performance_all_nordic, alternative = 'greater')
Welch Two Sample t-test
data: Force.Diff.Norm by Sport.2
t = 7.4127, df = 1313, p-value = 1.105e-13
alternative hypothesis: true difference in means between group Court and group Field is greater than 0
95 percent confidence interval:
0.05281774 Inf
sample estimates:
mean in group Court mean in group Field
0.09975077 0.03185696
There is a lot of statistical evidence for a difference in the means
of court sports vs field sports in maximum nordic bilateral mean force.
There is less but still statistically significant evidence for a
difference in the average imbalance and max imbalance between sport
types with field sports typically having more imbalance.
#performs a Welch's T-test for difference of means within court sports
t.test(Maximum.Nordic.Bilateral.Mean ~ Sport, data = court_all)
Welch Two Sample t-test
data: Maximum.Nordic.Bilateral.Mean by Sport
t = 1.9529, df = 555.95, p-value = 0.05133
alternative hypothesis: true difference in means between group Basketball and group Volleyball is not equal to 0
95 percent confidence interval:
-0.05339569 18.45108564
sample estimates:
mean in group Basketball mean in group Volleyball
334.0163 324.8174
t.test(Relative.Maximum.Nordic.Bilateral.Mean ~ Sport, data = court_all)
Welch Two Sample t-test
data: Relative.Maximum.Nordic.Bilateral.Mean by Sport
t = -4.8551, df = 377.59, p-value = 1.765e-06
alternative hypothesis: true difference in means between group Basketball and group Volleyball is not equal to 0
95 percent confidence interval:
-0.4441966 -0.1881154
sample estimates:
mean in group Basketball mean in group Volleyball
4.163935 4.480091
t.test(Nordic.MEAN.Imbalance ~ Sport, data = court_all)
Welch Two Sample t-test
data: Nordic.MEAN.Imbalance by Sport
t = -0.024763, df = 534.59, p-value = 0.9803
alternative hypothesis: true difference in means between group Basketball and group Volleyball is not equal to 0
95 percent confidence interval:
-0.9527264 0.9290056
sample estimates:
mean in group Basketball mean in group Volleyball
7.310454 7.322314
t.test(Impulse ~ Sport, data = court_all)
Welch Two Sample t-test
data: Impulse by Sport
t = -6.2874, df = 325.92, p-value = 1.037e-09
alternative hypothesis: true difference in means between group Basketball and group Volleyball is not equal to 0
95 percent confidence interval:
-1512.4152 -791.5294
sample estimates:
mean in group Basketball mean in group Volleyball
3829.585 4981.557
t.test(Force.Diff.Norm ~ Sport, data = court_all)
Welch Two Sample t-test
data: Force.Diff.Norm by Sport
t = -2.9617, df = 521.39, p-value = 0.003199
alternative hypothesis: true difference in means between group Basketball and group Volleyball is not equal to 0
95 percent confidence interval:
-0.07867392 -0.01592532
sample estimates:
mean in group Basketball mean in group Volleyball
0.08446838 0.13176800
There is a very small difference between these two sports, with
basketball being slightly stronger, but the p-value is almost
significant at the 0.05 level. No statistical signficance in terms of
imbalance.
#performs a Welch's T-test for difference of means within court sports
t.test(Maximum.Nordic.Bilateral.Mean ~ Sport, data = field_all)
Welch Two Sample t-test
data: Maximum.Nordic.Bilateral.Mean by Sport
t = -5.1833, df = 818.11, p-value = 2.748e-07
alternative hypothesis: true difference in means between group Lacrosse and group Soccer is not equal to 0
95 percent confidence interval:
-20.419348 -9.202067
sample estimates:
mean in group Lacrosse mean in group Soccer
287.9800 302.7908
t.test(Relative.Maximum.Nordic.Bilateral.Mean ~ Sport, data = field_all)
Welch Two Sample t-test
data: Relative.Maximum.Nordic.Bilateral.Mean by Sport
t = 2.2984, df = 711.59, p-value = 0.02183
alternative hypothesis: true difference in means between group Lacrosse and group Soccer is not equal to 0
95 percent confidence interval:
0.01349685 0.17164270
sample estimates:
mean in group Lacrosse mean in group Soccer
4.489158 4.396588
t.test(Nordic.MEAN.Imbalance ~ Sport, data = field_all)
Welch Two Sample t-test
data: Nordic.MEAN.Imbalance by Sport
t = 2.1357, df = 770.15, p-value = 0.03302
alternative hypothesis: true difference in means between group Lacrosse and group Soccer is not equal to 0
95 percent confidence interval:
0.07392564 1.75511822
sample estimates:
mean in group Lacrosse mean in group Soccer
8.281694 7.367172
t.test(Impulse ~ Sport, data = field_all)
Welch Two Sample t-test
data: Impulse by Sport
t = -12.988, df = 695.37, p-value < 2.2e-16
alternative hypothesis: true difference in means between group Lacrosse and group Soccer is not equal to 0
95 percent confidence interval:
-2048.749 -1510.681
sample estimates:
mean in group Lacrosse mean in group Soccer
3087.578 4867.293
t.test(Force.Diff.Norm ~ Sport, data = field_all)
Welch Two Sample t-test
data: Force.Diff.Norm by Sport
t = 2.3924, df = 873.65, p-value = 0.01695
alternative hypothesis: true difference in means between group Lacrosse and group Soccer is not equal to 0
95 percent confidence interval:
0.004232278 0.042893324
sample estimates:
mean in group Lacrosse mean in group Soccer
0.03963917 0.01607637
There is a lot of statistical evidence that there is a difference in
the means of maximum nordic bilateral mean force between the field
sports with soccer having a significantly higher mean than lacrosse.
There is statistical evidence of a difference in imbalance with lacrosse
having significantly more mean and max imbalance compared to soccer but
most likely also basketball and volleyball.
t.test(Nordic.MEAN.Imbalance ~ Sport, data = performance_all_nordic %>% filter(Sport %in% c('Volleyball', 'Basketball')))
Welch Two Sample t-test
data: Nordic.MEAN.Imbalance by Sport
t = -0.024763, df = 534.59, p-value = 0.9803
alternative hypothesis: true difference in means between group Basketball and group Volleyball is not equal to 0
95 percent confidence interval:
-0.9527264 0.9290056
sample estimates:
mean in group Basketball mean in group Volleyball
7.310454 7.322314
#anova test for differences
anova_result <- aov(Nordic.MAX.Imbalance ~ Sport, data = performance_all_nordic)
summary(anova_result)
Df Sum Sq Mean Sq F value Pr(>F)
Sport 3 510 169.92 3.911 0.00848 **
Residuals 1944 84452 43.44
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Using the anova test there is slight statistical evidence of a
difference in mean imbalance between sports and more for max imbalance
between sports.
Hip Data
#creating a dataset containing performance hip data across all sports
performance_all_hip <- rbind(performance_B_hip, performance_S_hip, performance_L_hip, performance_V_hip) %>%
mutate(Avg.Abd.Mean = (Hip.Abd.Left.MEAN + Hip.Abd.Right.MEAN) / 2,
Avg.Add.Mean = (Hip.Add.Left.MEAN + Hip.Add.Right.MEAN) / 2,
Avg.Abd.Max = (Hip.Abd.Left.MAX + Hip.Abd.Right.MAX) / 2,
Avg.Add.Max = (Hip.Add.Left.MAX + Hip.Add.Right.MAX) / 2,
Relative.Abd.Mean = Avg.Abd.Mean / Athlete.Bodyweight..kg.,
Relative.Add.Mean = Avg.Add.Mean / Athlete.Bodyweight..kg.,
Relative.Abd.Max = Avg.Abd.Max / Athlete.Bodyweight..kg.,
Relative.Add.Max = Avg.Add.Max / Athlete.Bodyweight..kg.,
Sport.2 = ifelse(Sport == 'Basketball' | Sport == 'Volleyball', 'Court', 'Field'))
#summarizes averages for variables of interest within each sport
performance_all_hip %>%
group_by(Sport) %>%
summarise(`Average Abd. Mean` = mean(Avg.Abd.Mean),
`Average Add. Mean` = mean(Avg.Add.Mean),
`Average Abd. Max` = mean(Avg.Abd.Max),
`Average Add. Max` = mean(Avg.Add.Max),
`Average Rel. Abd. Mean` = mean(Relative.Abd.Mean),
`Average Rel. Add. Mean` = mean(Relative.Add.Mean),
`Average Rel. Abd. Max` = mean(Relative.Abd.Max),
`Average Rel. Add. Max` = mean(Relative.Add.Max))
#creates a subset of just the field sports
field_all_hip <- performance_all_hip %>%
filter(Sport.2 == 'Field')
#creates a subset of just the court sports
court_all_hip <- performance_all_hip %>%
filter(Sport.2 == 'Court')
#creates a density plot of hip abduction across the 4 sports
ggplot(performance_all_hip, aes(x = Impulse, fill = Sport, color = Sport)) +
geom_density(alpha = 0.4) +
scale_fill_manual(values = c('#CFB87C', '#666666', '#000000', '#8C7853')) +
scale_color_manual(values = c('#CFB87C', '#666666', '#000000', '#8C7853')) +
labs(title = 'Distribution of Abd/Add Impulse Across Sports',
x = 'Impulse',
y = 'Density') +
theme_bw()

#creates a density plot for hip abduction/adduction impulse across sport type
ggplot(performance_all_hip, aes(x = Impulse, color = Sport.2, fill = Sport.2)) +
geom_density(alpha = 0.5) +
scale_fill_manual(values = c('#CFB87C', '#000000')) +
scale_color_manual(values = c('#CFB87C', '#000000')) +
labs(title = 'Distribution of Abd/Add Impulse Across Sports',
x = 'Impulse',
y = 'Density',
fill = 'Sport Type',
color = 'Sport Type') +
theme_bw()

#reads in the image of the normative data and normalizes the size
img <- image_read("add_wbb.png")
img_grob <- rasterGrob(img, interpolate = TRUE)
img_plot <- ggdraw() + draw_grob(img_grob, x = 0, y = 0, width = 1, height = 1)
#creates a plot of the CU data named "p"
p <- ggplot(performance_B_hip, aes(x = Avg.Add.Max)) +
geom_density(fill = '#CFB87C') +
labs(title = 'Distribution of Maximum Adduction Force',
x = 'Maximum Adduction Force (N)',
y = 'Density',
caption = 'CU Womens Basketball') +
geom_vline(xintercept = median(performance_B_hip$Avg.Add.Max), linetype = 'solid') +
geom_vline(xintercept = c(quantile(performance_B_hip$Avg.Add.Max, probs = c(0.01, 0.25, 0.75, 0.99))), linetype = 'dashed') +
scale_x_continuous(breaks = seq(from = 0, to = 1000, by = 50)) +
theme_bw()
#combines both the CU data density plot and puts normative image on the right
combined <- plot_grid(p, img_plot,
rel_widths = c(1.5, 1),
nrow = 1, # <- horizontal layout
align = "h") # <- align horizontally
#prints final graphic
combined
#performs a Welch's T-test for difference of means between variables of interest by sport type
t.test(Avg.Abd.Max ~ Sport.2, data = performance_all_hip, alternative = 'greater')
Welch Two Sample t-test
data: Avg.Abd.Max by Sport.2
t = 9.9963, df = 284.94, p-value < 2.2e-16
alternative hypothesis: true difference in means between group Court and group Field is greater than 0
95 percent confidence interval:
57.2211 Inf
sample estimates:
mean in group Court mean in group Field
350.3221 281.7870
t.test(Avg.Add.Max ~ Sport.2, data = performance_all_hip, alternative = 'greater')
Welch Two Sample t-test
data: Avg.Add.Max by Sport.2
t = 7.816, df = 262.2, p-value = 6.628e-14
alternative hypothesis: true difference in means between group Court and group Field is greater than 0
95 percent confidence interval:
45.49045 Inf
sample estimates:
mean in group Court mean in group Field
347.5856 289.9157
t.test(Relative.Abd.Max ~ Sport.2, data = performance_all_hip, alternative = 'greater')
Welch Two Sample t-test
data: Relative.Abd.Max by Sport.2
t = 5.1073, df = 270.35, p-value = 3.089e-07
alternative hypothesis: true difference in means between group Court and group Field is greater than 0
95 percent confidence interval:
0.3175289 Inf
sample estimates:
mean in group Court mean in group Field
4.632944 4.163806
t.test(Relative.Add.Max ~ Sport.2, data = performance_all_hip, alternative = 'greater')
Welch Two Sample t-test
data: Relative.Add.Max by Sport.2
t = 3.1297, df = 284.51, p-value = 0.0009659
alternative hypothesis: true difference in means between group Court and group Field is greater than 0
95 percent confidence interval:
0.1584972 Inf
sample estimates:
mean in group Court mean in group Field
4.627802 4.292515
There is a statistically significant difference in the means values
of average adduction and abduction max between the court and field
sports. This is also true for the relative adduction and abduction max,
although slightly less significant. The same applies for the mean
abduction/adduction stats as well.
#performs a Welch's T-test for difference of means within court sports
t.test(Avg.Abd.Max ~ Sport, data = court_all_hip)
Welch Two Sample t-test
data: Avg.Abd.Max by Sport
t = 2.0879, df = 202.5, p-value = 0.03806
alternative hypothesis: true difference in means between group Basketball and group Volleyball is not equal to 0
95 percent confidence interval:
0.9784126 34.2101994
sample estimates:
mean in group Basketball mean in group Volleyball
360.3042 342.7099
t.test(Avg.Add.Max ~ Sport, data = court_all_hip)
Welch Two Sample t-test
data: Avg.Add.Max by Sport
t = -0.041264, df = 205.8, p-value = 0.9671
alternative hypothesis: true difference in means between group Basketball and group Volleyball is not equal to 0
95 percent confidence interval:
-17.19365 16.48869
sample estimates:
mean in group Basketball mean in group Volleyball
347.3856 347.7381
t.test(Relative.Abd.Max ~ Sport, data = court_all_hip)
Welch Two Sample t-test
data: Relative.Abd.Max by Sport
t = -1.0985, df = 197.26, p-value = 0.2733
alternative hypothesis: true difference in means between group Basketball and group Volleyball is not equal to 0
95 percent confidence interval:
-0.33658083 0.09575887
sample estimates:
mean in group Basketball mean in group Volleyball
4.564629 4.685040
t.test(Relative.Add.Max ~ Sport, data = court_all_hip)
Welch Two Sample t-test
data: Relative.Add.Max by Sport
t = -2.58, df = 200.62, p-value = 0.01059
alternative hypothesis: true difference in means between group Basketball and group Volleyball is not equal to 0
95 percent confidence interval:
-0.59681864 -0.07973619
sample estimates:
mean in group Basketball mean in group Volleyball
4.435882 4.774159
There is a statistically significant difference in the means of
average abduction max with basketball being higher and relative
adduction max with volleyball being higher. Also important to note that
average adduction maxs are almost identical between the sports and have
a p-value of 0.9671. Volleyball is greater in terms of relative force in
both.
#performs a Welch's T-test for difference of means within field sports
t.test(Avg.Abd.Max ~ Sport, data = field_all_hip)
Welch Two Sample t-test
data: Avg.Abd.Max by Sport
t = -1.781, df = 47.938, p-value = 0.08125
alternative hypothesis: true difference in means between group Lacrosse and group Soccer is not equal to 0
95 percent confidence interval:
-57.482751 3.482574
sample estimates:
mean in group Lacrosse mean in group Soccer
274.2115 301.2115
t.test(Avg.Add.Max ~ Sport, data = field_all_hip)
Welch Two Sample t-test
data: Avg.Add.Max by Sport
t = -5.6946, df = 50.24, p-value = 6.414e-07
alternative hypothesis: true difference in means between group Lacrosse and group Soccer is not equal to 0
95 percent confidence interval:
-109.84946 -52.56943
sample estimates:
mean in group Lacrosse mean in group Soccer
267.1303 348.3397
t.test(Relative.Abd.Max ~ Sport, data = field_all_hip)
Welch Two Sample t-test
data: Relative.Abd.Max by Sport
t = 1.6377, df = 49.04, p-value = 0.1079
alternative hypothesis: true difference in means between group Lacrosse and group Soccer is not equal to 0
95 percent confidence interval:
-0.0760297 0.7458475
sample estimates:
mean in group Lacrosse mean in group Soccer
4.257773 3.922864
t.test(Relative.Add.Max ~ Sport, data = field_all_hip)
Welch Two Sample t-test
data: Relative.Add.Max by Sport
t = -1.8352, df = 56.879, p-value = 0.07171
alternative hypothesis: true difference in means between group Lacrosse and group Soccer is not equal to 0
95 percent confidence interval:
-0.80852340 0.03526181
sample estimates:
mean in group Lacrosse mean in group Soccer
4.184036 4.570667
Most are almost significant with the difference in average adduction
max being very significant. Soccer is greater in both strength forces on
average and the relative adduction but lacross is stronger on average in
the relative abduction.
#anova test for differences
anova_result <- aov(Bilateral.Hip.Abduction.Adduction.Ratio ~ Sport, data = performance_all_hip)
summary(anova_result)
Df Sum Sq Mean Sq F value Pr(>F)
Sport 3 91 30.23 0.875 0.454
Residuals 380 13128 34.55
Using anova test there is no statistical evidence of a difference in
means between sports for average/max hip adduction imbalance or
bilateral hip abduction adduction ratio. There is however very slight
statistical evidence of a difference in means between the sports for
average/max hip abduction imbalance.
t.test(Impulse ~ Sport, data = performance_all_hip %>% filter(Sport %in% c('Soccer', 'Basketball')))
Welch Two Sample t-test
data: Impulse by Sport
t = 0.047169, df = 77.62, p-value = 0.9625
alternative hypothesis: true difference in means between group Basketball and group Soccer is not equal to 0
95 percent confidence interval:
-264.7115 277.5584
sample estimates:
mean in group Basketball mean in group Soccer
2065.522 2059.098
LS0tDQp0aXRsZTogIkRhdGEgQW5hbHlzaXMgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7cn0NCiNBdXRob3JzOiBbU3lkbmV5IFN0YW50b24sIENhcnRlciBaYm9yb3dza2ldICAgDQojQXV0aG9yIERhdGU6IDA3LzI4LzIwMjUNCiNQdXJwb3NlOiBUaGUgcHVycG9zZSBvZiB0aGlzIG5vdGVib29rIGlzIHRvIGhvdXNlIGFsbCBkYXRhIHNldCB0cmFuc2Zvcm1hdGlvbiwgY2xlYW5zaW5nLCB2aXN1YWxpemF0aW9uLCBzdGF0aXN0aWNhbCBhbmFseXNpcywgYW5kIG5vdGUtdGFraW5nIGZvciB0aGUgMjAyNSBDVSBBdGhsZXRpYyBEZXBhcnRtZW50IFNwb3J0cyBTY2llbmNlIEludGVybnNoaXAgUHJvZ3JhbQ0KDQojTEFTVCBVUERBVEVEOiAwNy8yOC8yMDI1DQoNCiNJbmNsdWRpbmcgaGVscGZ1bCBsaWJyYXJpZXMNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGFvZCkNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KGN1dHBvaW50cikgI3RocmVzaG9sZCBvcHRpbWl6YXRpb24NCmxpYnJhcnkocFJPQykgICAgICAjdGhyZXNob2xkIG9wdGltaXphdGlvbg0KbGlicmFyeShncmlkKSAgICAgICNyZWNyZWF0ZSBub3JtYXRpdmUgZGF0YQ0KbGlicmFyeShwbmcpICAgICAgICNyZWNyZWF0ZSBub3JtYXRpdmUgZGF0YQ0KbGlicmFyeShjb3dwbG90KSAgICNyZWNyZWF0ZSBub3JtYXRpdmUgZGF0YQ0KbGlicmFyeShtYWdpY2spICAgICNyZWNyZWF0ZSBub3JtYXRpdmUgZGF0YQ0KYGBgDQoNCiMgTG9hZGluZyBEYXRhc2V0cw0KYGBge3J9DQojV29tZW5zIGJhc2tldGJhbGwgZGF0YXNldHMNCkluY2lkZW50X0IgPC0gcmVhZC5jc3YoImRhdGEtc2V0cy9JbmNpZGVudCBSZXBvcnQgV0JCLmNzdiIpDQpEeW5hbW9fQiA8LSByZWFkLmNzdigiZGF0YS1zZXRzL1ZBTEQgLSBEeW5hbW8gV0JCLmNzdiIpDQpGb3JjZWRlY2tzX0IgPC0gcmVhZC5jc3YoImRhdGEtc2V0cy9WQUxEIC0gRm9yY2VEZWNrcyBXQkIuY3N2IikNClBlcmZvcm1hbmNlX0IgPC0gcmVhZC5jc3YoImRhdGEtc2V0cy9WQUxEIC0gUGVyZm9ybWFuY2UgVGVzdCBXQkIuY3N2IikNCg0KI3dvbWVucyBzb2NjZXIgZGF0YXNldHMNCkluY2lkZW50X1MgPC0gcmVhZC5jc3YoImRhdGEtc2V0cy9JbmNpZGVudCBSZXBvcnQgV1NPQy5jc3YiKQ0KRHluYW1vX1MgPC0gcmVhZC5jc3YoImRhdGEtc2V0cy9WQUxEIC0gRHluYW1vIFdTT0MuY3N2IikNCkZvcmNlZGVja3NfUyA8LSByZWFkLmNzdigiZGF0YS1zZXRzL1ZBTEQgLSBGb3JjZURlY2tzIFdTT0MuY3N2IikNClBlcmZvcm1hbmNlX1MgPC0gcmVhZC5jc3YoImRhdGEtc2V0cy9WQUxEIC0gUGVyZm9ybWFuY2UgVGVzdCBXU09DLmNzdiIpDQoNCiN3b21lbnMgbGFjcm9zc2UgZGF0YXNldHMNCkluY2lkZW50X0wgPC0gcmVhZC5jc3YoImRhdGEtc2V0cy9JbmNpZGVudCBSZXBvcnQgV0xBWC5jc3YiKQ0KRHluYW1vX0wgPC0gcmVhZC5jc3YoImRhdGEtc2V0cy9WQUxEIC0gRHluYW1vIFdMQVguY3N2IikNCkZvcmNlZGVja3NfTCA8LSByZWFkLmNzdigiZGF0YS1zZXRzL1ZBTEQgLSBGb3JjZURlY2tzIFdMQVguY3N2IikNClBlcmZvcm1hbmNlX0wgPC0gcmVhZC5jc3YoImRhdGEtc2V0cy9WQUxEIC0gUGVyZm9ybWFuY2UgVGVzdCBXTEF4ICgxKS5jc3YiKQ0KDQojd29tZW5zIHZvbGxleWJhbGwgZGF0YXNldHMgDQpJbmNpZGVudF9WIDwtIHJlYWQuY3N2KCJkYXRhLXNldHMvSW5jaWRlbnQgUmVwb3J0IFdWQi5jc3YiKQ0KRHluYW1vX1YgPC0gcmVhZC5jc3YoImRhdGEtc2V0cy9WQUxEIC0gRHluYW1vIFdWQi5jc3YiKQ0KRm9yY2VkZWNrc19WIDwtIHJlYWQuY3N2KCJkYXRhLXNldHMvVkFMRCAtIEZvcmNlRGVja3MgV1ZCLmNzdiIpDQpQZXJmb3JtYW5jZV9WIDwtIHJlYWQuY3N2KCJkYXRhLXNldHMvVkFMRCAtIFBlcmZvcm1hbmNlIFRlc3QgV1ZCLmNzdiIpDQpgYGANCg0KIyBEYXRhIENsZWFuaW5nDQoxLiBJbmNpZGVudCBEYXRhc2V0cw0KDQojSW5jaWRlbnQgQmFza2V0YmFsbCBEYXRhDQpgYGB7cn0NCiNCQVNLRVRCQUxMIEluY2lkZW50IGRhdGFzZXQNCkluY2lkZW50X0IgPC0gSW5jaWRlbnRfQiAlPiUgICAgICAgICAgICAgICAgICAgICMxODkgLT4gMTI4IG9icy4NCmZpbHRlcihJbmNpZGVudC5UeXBlPT0iSW5qdXJ5IikgJT4lDQpmaWx0ZXIoU3RhdHVzICVpbiUgYygiT3V0IiwgIkFzIFRvbGVyYXRlZCIpKSAlPiUNCmZpbHRlcihSZXN1bHQub2YuU3BvcnQuUGFydGljaXBhdGlvbj09IlllcyIpICAlPiUNCnNlbGVjdCgtUmVzdWx0Lm9mLlNwb3J0LlBhcnRpY2lwYXRpb24pDQoNCmluY2lkZW50X0IgPC0gc3Vic2V0KEluY2lkZW50X0Isc2VsZWN0PWMoImFub25faWQiLCJEYXRlIiwiU3BvcnQiLCAiUG9zaXRpb24iLCAiRGF0ZS5vZi5Jbmp1cnkuLi5PbnNldC5vZi5zeW1wdG9tcyIsICJTaWRlIiwgIkJvZHkuUGFydC4iLCJUb3RhbC5UaW1lLkluanVyZWQiLCAiVGlzc3VlLlR5cGUiLCJPU0lDUzE0LkNvZGUiLCJPU0lDUzEwLkRpYWdub3NpcyIsIkZpbmFsLkRpYWdub3NpcyIsICJSZWN1cnJlbmNlLm9mLkluanVyeSIsICJJbmp1cnkuUHJvZ25vc2lzIiwgIkdlbmVyYWwubWVjaGFuaXNtIiwiU3BlY2lmaWMuTWVjaGFuaXNtIiwiSW5qdXJlZC5Qb3NpdGlvbiIsICJNb250aCIsICJZZWFyIiwiU3RhdHVzIiwiU2Vhc29uLiIsIlN0YXJ0Lm9mLlN0YXR1cyIsICJFbmQuRGF0ZSIsICJUb3RhbC5UaW1lLkluanVyZWQiKSkgICNhZGQsIkluanVyZWQuUG9zaXRpb24iLA0KICAgICAgICAjNTMgb2JzLiArIDI3IHZhcnMuDQoNCiNMb3dlciBib2R5IGluanVyaWVzIA0KbG93ZXJfYm9keSA8LSBjKCJUaGlnaCIsIkFua2xlIiwiTG93ZXIgbGVnIiwiS25lZSIsIkZvb3QiLCJHcm9pbi9oaXAiKQ0KaW5jaWRlbnRfQiRMQi5Jbmp1cnkgPC0gaWZlbHNlKGluY2lkZW50X0IkQm9keS5QYXJ0LiAlaW4lIGMoIlRoaWdoIiwgIkFua2xlIiwgIkxvd2VyIGxlZyIsICJLbmVlIiwgIkZvb3QiLCAiR3JvaW4vaGlwIiksMSwwKSAjbG93ZXIgYm9keSBJbmp1cnkgQmluYXJ5DQpzdW0oaW5jaWRlbnRfQiRMQi5Jbmp1cnkpDQoNCiNBQ0wgaW5qdXJ5IChtb3N0IGludGVuc2UgTEIgaW5qdXJ5KQ0KaW5jaWRlbnRfQiRBQ0wgPC0gaWZlbHNlKGluY2lkZW50X0IkT1NJQ1MxNC5Db2RlICVpbiUgYygiS0wxIiwiS0xBIiksMSwwKQ0Kc3VtKGluY2lkZW50X0IkQUNMKQ0KI0hTSSBpbmp1cnkgKG92ZXJ1c2UgaW5qdXJ5KQ0KaW5jaWRlbnRfQiRIU0kgPC0gaWZlbHNlKGluY2lkZW50X0IkT1NJQ1MxNC5Db2RlICVpbiUgYygiVE0xIiwiVE1CIiwiVE1TIiksMSwwKQ0Kc3VtKGluY2lkZW50X0IkSFNJKQ0KDQojMTIvNS8yMy0xLzIvMjUgREFURSBSQU5HRSAoMiB5ZWFycykNCg0KI2NvbnZlcnRpbmcgYWxsIGRhdGVzDQppbmNpZGVudF9iIDwtIGluY2lkZW50X0IgJT4lDQptdXRhdGUoVG90YWwuVGltZS5Jbmp1cmVkID0gc3VtKFRvdGFsLlRpbWUuSW5qdXJlZCwgbmEucm0gPSBUUlVFKSwNCiAgICAgICBEYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAnJW0vJWQvJVknKSwNCiAgICAgICBTdGFydC5vZi5TdGF0dXM9YXMuRGF0ZShTdGFydC5vZi5TdGF0dXMsZm9ybWF0PSclbS8lZC8lWScpLA0KICAgICAgIEVuZC5EYXRlPSBhcy5EYXRlKEVuZC5EYXRlLCBmb3JtYXQ9JyVtLyVkLyVZJyksDQogICAgICAgRGF0ZS5vZi5Jbmp1cnkuLi5PbnNldC5vZi5zeW1wdG9tcz0gYXMuRGF0ZShEYXRlLm9mLkluanVyeS4uLk9uc2V0Lm9mLnN5bXB0b21zLCBmb3JtYXQ9JyVtLyVkLyVZJykpDQoNCiNjcmVhdGUgYSBsZW5ndGggb2Ygc3RhdHVzIHZhcmlhYmxlIChPdXQsIGxpbWl0ZWQsYXMgdG9sZXJhdGVkLCBmdWxsIGdvKQ0KaW5jaWRlbnRfYiRMZW5ndGgub2YuU3RhdHVzIDwtIGRpZmZ0aW1lKGluY2lkZW50X2IkRW5kLkRhdGUsIGluY2lkZW50X2IkU3RhcnQub2YuU3RhdHVzLHVuaXRzPWMoImRheXMiKSkNCg0KbGlicmFyeShzdHJpbmdyKQ0KI3JlbmFtZSBvbmUgZGF0YXBvaW50IGZyb20gcG9zaXRpb24NCmluY2lkZW50X2IgPC0gaW5jaWRlbnRfYiAlPiUNCiAgbXV0YXRlKFBvc2l0aW9uPWNhc2Vfd2hlbigNCiAgICBzdHJfZGV0ZWN0KFBvc2l0aW9uLCAiUHJpbWFyeTogRm9yd2FyZCIpfiAiRm9yd2FyZCIsDQogICAgc3RyX2RldGVjdChQb3NpdGlvbiwgIkZvcndhcmQiKX4gIkZvcndhcmQiLA0KICAgIHN0cl9kZXRlY3QoUG9zaXRpb24sICJDZW50ZXIiKX4gIkNlbnRlciIsDQogICAgc3RyX2RldGVjdChQb3NpdGlvbiwgIkd1YXJkIil+ICJHdWFyZCIsDQogICAgVFJVRX5Qb3NpdGlvbg0KICApKQ0KI3JlbmFtZSBzcG9ydCBjb2x1bW4gdG8gYmV0dGVyIGNvbXBhcmUgd2hlbiBqb2luaW5nIGRhdGFzZXRzDQppbmNpZGVudF9iIDwtIGluY2lkZW50X2IgJT4lDQogIG11dGF0ZShTcG9ydD1jYXNlX3doZW4oDQogICAgc3RyX2RldGVjdChTcG9ydCwgIlByaW1hcnk6IEJBU0tFVEJBTEwiKX4gIkJhc2tldGJhbGwiLA0KICAgIHN0cl9kZXRlY3QoU3BvcnQsICJCQVNLRVRCQUxMIil+ICJCYXNrZXRiYWxsIg0KICApKQ0KYGBgDQpJbiB3b21lbnMgYmFza2V0YmFsbCB3ZSBoYXZlIDQyIHRvdGFsIGxvd2VyIGJvZHkgaW5qdXJpZXMsIDEgb2YgdGhvc2UgaW5qdXJpZXMgYXJlIEFDTCBpbmp1cmllcywgYW5kIG5vbmUgYXJlIEhTSSBpbmp1cmllcy4NCg0KI0luY2lkZW50IFNvY2NlciBEYXRhDQpgYGB7cn0NCiNTT0NDRVIgSU5DSURFTlQgZGF0YXNldA0KSW5jaWRlbnRfUyA8LSBJbmNpZGVudF9TICU+JSAgICAgICAgICAgICAgICAgICAgIzM2MSAtPiAyODggb2JzLg0KZmlsdGVyKEluY2lkZW50LlR5cGU9PSJJbmp1cnkiKSAlPiUNCmZpbHRlcihTdGF0dXMgJWluJSBjKCJPdXQiLCAiQXMgVG9sZXJhdGVkIikpICU+JQ0KZmlsdGVyKFJlc3VsdC5vZi5TcG9ydC5QYXJ0aWNpcGF0aW9uPT0iWWVzIikgJT4lDQpzZWxlY3QoLVJlc3VsdC5vZi5TcG9ydC5QYXJ0aWNpcGF0aW9uKQ0KDQppbmNpZGVudF9TIDwtIHN1YnNldChJbmNpZGVudF9TLHNlbGVjdD1jKCJhbm9uX2lkIiwiRGF0ZSIsIlNwb3J0IiwgIlBvc2l0aW9uIiwgIkRhdGUub2YuSW5qdXJ5Li4uT25zZXQub2Yuc3ltcHRvbXMiLCAiU2lkZSIsICJCb2R5LlBhcnQuIiwgIlRvdGFsLlRpbWUuSW5qdXJlZCIsICJUaXNzdWUuVHlwZSIsIk9TSUNTMTQuQ29kZSIsIk9TSUNTMTAuRGlhZ25vc2lzIiwgIkZpbmFsLkRpYWdub3NpcyIsICJSZWN1cnJlbmNlLm9mLkluanVyeSIsICJJbmp1cnkuUHJvZ25vc2lzIiwgIkdlbmVyYWwubWVjaGFuaXNtIiwiU3BlY2lmaWMuTWVjaGFuaXNtIiwiSW5qdXJlZC5XaGlsZS4iLCAiTW9udGgiLCAiWWVhciIsIkluY2lkZW50LlR5cGUiLCJTdGF0dXMiLCAiU2Vhc29uLiIsIlN0YXJ0Lm9mLlN0YXR1cyIsICJFbmQuRGF0ZSIpKQ0KICAgICAgICAjODggb2JzLiArIDI3IHZhcnMuDQoNCiNMb3dlciBib2R5IGluanVyaXkgQmluYXJ5DQppbmNpZGVudF9TJExCLkluanVyeSA8LSBpZmVsc2UoaW5jaWRlbnRfUyRCb2R5LlBhcnQuICVpbiUgYygiVGhpZ2giLCAiQW5rbGUiLCAiTG93ZXIgbGVnIiwgIktuZWUiLCAiRm9vdCIsICJHcm9pbi9oaXAiKSwxLDApDQpzdW0oaW5jaWRlbnRfUyRMQi5Jbmp1cnkpDQoNCiNBQ0wgaW5qdXJ5IChtb3N0IGludGVuc2UgTEIgaW5qdXJ5KQ0KaW5jaWRlbnRfUyRBQ0wgPC0gaWZlbHNlKGluY2lkZW50X1MkT1NJQ1MxNC5Db2RlICVpbiUgYygiS0wxIiwiS0xBIiksMSwwKQ0Kc3VtKGluY2lkZW50X1MkQUNMKQ0KI0hTSSBpbmp1cnkgKG92ZXJ1c2UgaW5qdXJ5KQ0KaW5jaWRlbnRfUyRIU0kgPC0gaWZlbHNlKGluY2lkZW50X1MkT1NJQ1MxNC5Db2RlICVpbiUgYygiVE0xIiwiVE1CIiwiVE1TIiksMSwwKQ0Kc3VtKGluY2lkZW50X1MkSFNJKQ0KDQojNS84LzIzLSAxLzE1LzI1ICh5ZWFyIGFuZCBhIGhhbGYgaXNoKQ0KDQojY29udmVydGluZyBhbGwgZGF0ZXMNCmluY2lkZW50X3MgPC0gaW5jaWRlbnRfUyAlPiUNCm11dGF0ZShUb3RhbC5UaW1lLkluanVyZWQgPSBzdW0oVG90YWwuVGltZS5Jbmp1cmVkLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgIERhdGUgPSBhcy5EYXRlKERhdGUsIGZvcm1hdCA9ICclbS8lZC8lWScpLA0KICAgICAgIFN0YXJ0Lm9mLlN0YXR1cz1hcy5EYXRlKFN0YXJ0Lm9mLlN0YXR1cyxmb3JtYXQ9JyVtLyVkLyVZJyksDQogICAgICAgRW5kLkRhdGU9IGFzLkRhdGUoRW5kLkRhdGUsIGZvcm1hdD0nJW0vJWQvJVknKSwNCiAgICAgICBEYXRlLm9mLkluanVyeS4uLk9uc2V0Lm9mLnN5bXB0b21zPSBhcy5EYXRlKERhdGUub2YuSW5qdXJ5Li4uT25zZXQub2Yuc3ltcHRvbXMsIGZvcm1hdD0nJW0vJWQvJVknKSwNCiAgICAgICBTcG9ydD1jYXNlX3doZW4oDQogICAgc3RyX2RldGVjdChTcG9ydCwgIlNPQ0NFUiIpfiAiU29jY2VyIiAgICNyZW5hbWUgc3BvcnQgY29sdW1uIHRvIGJldHRlciBjb21wYXJlIHdoZW4gam9pbmluZyBkYXRhc2V0cw0KICApKQ0KDQojY3JlYXRlIGEgbGVuZ3RoIG9mIHN0YXR1cyB2YXJpYWJsZSAoT3V0LCBsaW1pdGVkLGFzIHRvbGVyYXRlZCwgZnVsbCBnbykNCmluY2lkZW50X3MkTGVuZ3RoLm9mLlN0YXR1cyA8LSBkaWZmdGltZShpbmNpZGVudF9zJEVuZC5EYXRlLCBpbmNpZGVudF9zJFN0YXJ0Lm9mLlN0YXR1cyx1bml0cz1jKCJkYXlzIikpDQpgYGANCkluIHdvbWVuJ3Mgc29jY2VyIHRoZXJlIGlzIGEgdG90YWwgb2YgNzYgbG93ZXIgYm9keSBpbmp1cmllcywgd2l0aCAxIG9mIHRoZW0gYmVpbmcgQUNMIGluanVyaWVzLCBhbmQgMiBiZWluZyBIU0kgaW5qdXJpZXMuDQoNCiNJbmNpZGVudCBMYWNyb3NzZSBEYXRhDQpgYGB7cn0NCiNMQUNST1NTRSBpbmNpZGVudCBkYXRhc2V0IA0KSW5jaWRlbnRfTCA8LSBJbmNpZGVudF9MICU+JSAgICAgICAgICAgICAgICAgICAgIzEzOSAtPiA4NiBvYnMuDQpmaWx0ZXIoSW5jaWRlbnQuVHlwZT09IkluanVyeSIpICU+JQ0KZmlsdGVyKFN0YXR1cyAlaW4lIGMoIk91dCIsICJBcyBUb2xlcmF0ZWQiKSkgJT4lDQpmaWx0ZXIoUmVzdWx0Lm9mLlNwb3J0LlBhcnRpY2lwYXRpb249PSJZZXMiKSAlPiUNCnNlbGVjdCgtUmVzdWx0Lm9mLlNwb3J0LlBhcnRpY2lwYXRpb24pDQoNCmluY2lkZW50X0wgPC0gc3Vic2V0KEluY2lkZW50X0wsc2VsZWN0PWMoImFub25faWQiLCJEYXRlIiwiU3BvcnQiLCAiUG9zaXRpb24iLCAiRGF0ZS5vZi5Jbmp1cnkuLi5PbnNldC5vZi5zeW1wdG9tcyIsICJTaWRlIiwgIkJvZHkuUGFydC4iLCAiVGlzc3VlLlR5cGUiLCJPU0lDUzE0LkNvZGUiLCJPU0lDUzEwLkRpYWdub3NpcyIsICJGaW5hbC5EaWFnbm9zaXMiLCAiUmVjdXJyZW5jZS5vZi5Jbmp1cnkiLCAiSW5qdXJ5LlByb2dub3NpcyIsICJHZW5lcmFsLm1lY2hhbmlzbSIsIlNwZWNpZmljLk1lY2hhbmlzbSIsICJJbmp1cmVkLldoaWxlLiIsICJNb250aCIsICJZZWFyIiwiSW5jaWRlbnQuVHlwZSIsIlN0YXR1cyIsICJTZWFzb24uIiwiU3RhcnQub2YuU3RhdHVzIiwgIkVuZC5EYXRlIiwgIlRvdGFsLlRpbWUuSW5qdXJlZCIpKSAgIzM0b2JzIA0KDQojTG93ZXIgYm9keSBpbmp1cnkgYmluYXJ5DQppbmNpZGVudF9MJExCLkluanVyeSA8LSBpZmVsc2UoaW5jaWRlbnRfTCRCb2R5LlBhcnQuICVpbiUgYygiVGhpZ2giLCAiQW5rbGUiLCAiTG93ZXIgbGVnIiwgIktuZWUiLCAiRm9vdCIsICJHcm9pbi9oaXAiKSwxLDApDQpzdW0oaW5jaWRlbnRfTCRMQi5Jbmp1cnkpDQoNCiNBQ0wgaW5qdXJ5IChtb3N0IGludGVuc2UgTEIgaW5qdXJ5KQ0KaW5jaWRlbnRfTCRBQ0wgPC0gaWZlbHNlKGluY2lkZW50X0wkT1NJQ1MxNC5Db2RlICVpbiUgYygiS0wxIiwiS0xBIiksMSwwKQ0Kc3VtKGluY2lkZW50X0wkQUNMKQ0KI0hTSSBpbmp1cnkgKG92ZXJ1c2UgaW5qdXJ5KQ0KaW5jaWRlbnRfTCRIU0kgPC0gaWZlbHNlKGluY2lkZW50X0wkT1NJQ1MxNC5Db2RlICVpbiUgYygiVE0xIiwiVE1CIiwiVE1TIiksMSwwKQ0Kc3VtKGluY2lkZW50X0wkSFNJKQ0KDQojNC8xMi8yMy00LzE4LzI1ICgyIHllYXJzKQ0KDQojY29udmVydGluZyBhbGwgZGF0ZXMNCmluY2lkZW50X2wgPC0gaW5jaWRlbnRfTCAlPiUNCm11dGF0ZShUb3RhbC5UaW1lLkluanVyZWQgPSBzdW0oVG90YWwuVGltZS5Jbmp1cmVkLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgIERhdGUgPSBhcy5EYXRlKERhdGUsIGZvcm1hdCA9ICclbS8lZC8lWScpLA0KICAgICAgIFN0YXJ0Lm9mLlN0YXR1cz1hcy5EYXRlKFN0YXJ0Lm9mLlN0YXR1cyxmb3JtYXQ9JyVtLyVkLyVZJyksDQogICAgICAgRW5kLkRhdGU9IGFzLkRhdGUoRW5kLkRhdGUsIGZvcm1hdD0nJW0vJWQvJVknKSwNCiAgICAgICBEYXRlLm9mLkluanVyeS4uLk9uc2V0Lm9mLnN5bXB0b21zPSBhcy5EYXRlKERhdGUub2YuSW5qdXJ5Li4uT25zZXQub2Yuc3ltcHRvbXMsIGZvcm1hdD0nJW0vJWQvJVknKSwNCiAgICAgICBTcG9ydD1jYXNlX3doZW4oDQogICAgc3RyX2RldGVjdChTcG9ydCwgIkxBQ1JPU1NFIil+ICJMYWNyb3NzZSINCiAgKQ0KKQ0KDQojY3JlYXRlIGEgbGVuZ3RoIG9mIHN0YXR1cyB2YXJpYWJsZSAoT3V0LCBsaW1pdGVkLGFzIHRvbGVyYXRlZCwgZnVsbCBnbykNCmluY2lkZW50X2wkTGVuZ3RoLm9mLlN0YXR1cyA8LSBkaWZmdGltZShpbmNpZGVudF9sJEVuZC5EYXRlLCBpbmNpZGVudF9sJFN0YXJ0Lm9mLlN0YXR1cyx1bml0cz1jKCJkYXlzIikpDQpgYGANCkluIHdvbWVucyBsYWNyb3NzZSAzMSBsb3dlciBib2R5IGluanVyaWVzIG9jY3VycmVkLCAzIGJlaW5nIEFDTCByZWxhdGVkLCA0IGJlaW5nIEhTSSBpbmp1cnkgcmVsYXRlZC4NCg0KI0luY2lkZW50IFZvbGxleWJhbGwgRGF0YQ0KYGBge3J9DQojVk9MTEVZQkFMTCBpbmNpZGVudCBkYXRhc2V0DQpJbmNpZGVudF9WIDwtIEluY2lkZW50X1YgJT4lICAgICAgICAgICAgICAgICAgICAjMjIwIC0+IDEzNSBvYnMuDQpmaWx0ZXIoSW5jaWRlbnQuVHlwZT09IkluanVyeSIpICU+JQ0KZmlsdGVyKFN0YXR1cyAlaW4lIGMoIk91dCIsICJBcyBUb2xlcmF0ZWQiKSkgJT4lDQpmaWx0ZXIoUmVzdWx0Lm9mLlNwb3J0LlBhcnRpY2lwYXRpb249PSJZZXMiKSAlPiUNCnNlbGVjdCgtUmVzdWx0Lm9mLlNwb3J0LlBhcnRpY2lwYXRpb24pDQoNCmluY2lkZW50X1YgPC0gc3Vic2V0KEluY2lkZW50X1Ysc2VsZWN0PWMoImFub25faWQiLCJEYXRlIiwiU3BvcnQiLCAiUG9zaXRpb24iLCAiRGF0ZS5vZi5Jbmp1cnkuLi5PbnNldC5vZi5zeW1wdG9tcyIsICJTaWRlIiwgIkJvZHkuUGFydC4iLCAiVG90YWwuVGltZS5Jbmp1cmVkIiwgIlRpc3N1ZS5UeXBlIiwiT1NJQ1MxNC5Db2RlIiwiT1NJQ1MxMC5EaWFnbm9zaXMiLCAiRmluYWwuRGlhZ25vc2lzIiwgIlJlY3VycmVuY2Uub2YuSW5qdXJ5IiwgIkluanVyeS5Qcm9nbm9zaXMiLCAiR2VuZXJhbC5tZWNoYW5pc20iLCJTcGVjaWZpYy5NZWNoYW5pc20iLCJJbmp1cmVkLldoaWxlLiIsICJNb250aCIsICJZZWFyIiwiU3RhdHVzIiwgIlNlYXNvbi4iLCJTdGFydC5vZi5TdGF0dXMiLCAiRW5kLkRhdGUiLCAiVG90YWwuVGltZS5Jbmp1cmVkIikpDQogICAgICAgICM1MiArMjMgdmFycy4NCg0KI0xvd2VyIGJvZHkgaW5qdXJ5IGJpbmFyeQ0KaW5jaWRlbnRfViRMQi5Jbmp1cnkgPC0gaWZlbHNlKGluY2lkZW50X1YkQm9keS5QYXJ0LiAlaW4lIGMoIlRoaWdoIiwgIkFua2xlIiwgIkxvd2VyIGxlZyIsICJLbmVlIiwgIkZvb3QiLCAiR3JvaW4vaGlwIiksMSwwKQ0Kc3VtKGluY2lkZW50X1YkTEIuSW5qdXJ5KQ0KDQojQUNMIGluanVyeSAobW9zdCBpbnRlbnNlIExCIGluanVyeSkNCmluY2lkZW50X1YkQUNMIDwtIGlmZWxzZShpbmNpZGVudF9WJE9TSUNTMTQuQ29kZSAlaW4lIGMoIktMMSIsIktMQSIpLDEsMCkNCnN1bShpbmNpZGVudF9WJEFDTCkNCiNIU0kgaW5qdXJ5IChvdmVydXNlIGluanVyeSkNCmluY2lkZW50X1YkSFNJIDwtIGlmZWxzZShpbmNpZGVudF9WJE9TSUNTMTQuQ29kZSAlaW4lIGMoIlRNMSIsIlRNQiIsIlRNUyIpLDEsMCkNCnN1bShpbmNpZGVudF9WJEhTSSkNCg0KIzEvMTYvMjQtOS84LzI0ICg5IE1PTlRIUykNCg0KI2NvbnZlcnRpbmcgYWxsIGRhdGVzDQppbmNpZGVudF92IDwtIGluY2lkZW50X1YgJT4lDQptdXRhdGUoVG90YWwuVGltZS5Jbmp1cmVkID0gc3VtKFRvdGFsLlRpbWUuSW5qdXJlZCwgbmEucm0gPSBUUlVFKSwNCiAgICAgICBEYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAnJW0vJWQvJVknKSwNCiAgICAgICBTdGFydC5vZi5TdGF0dXM9YXMuRGF0ZShTdGFydC5vZi5TdGF0dXMsZm9ybWF0PSclbS8lZC8lWScpLA0KICAgICAgIEVuZC5EYXRlPSBhcy5EYXRlKEVuZC5EYXRlLCBmb3JtYXQ9JyVtLyVkLyVZJyksDQogICAgICAgRGF0ZS5vZi5Jbmp1cnkuLi5PbnNldC5vZi5zeW1wdG9tcz0gYXMuRGF0ZShEYXRlLm9mLkluanVyeS4uLk9uc2V0Lm9mLnN5bXB0b21zLCBmb3JtYXQ9JyVtLyVkLyVZJyksDQogICAgICAgU3BvcnQ9Y2FzZV93aGVuKA0KICAgIHN0cl9kZXRlY3QoU3BvcnQsICJWT0xMRVlCQUxMIil+ICJWb2xsZXliYWxsIg0KICApDQopDQoNCiNjcmVhdGUgYSBsZW5ndGggb2Ygc3RhdHVzIHZhcmlhYmxlIChPdXQsIGxpbWl0ZWQsYXMgdG9sZXJhdGVkLCBmdWxsIGdvKQ0KaW5jaWRlbnRfdiRMZW5ndGgub2YuU3RhdHVzIDwtIGRpZmZ0aW1lKGluY2lkZW50X3YkRW5kLkRhdGUsIGluY2lkZW50X3YkU3RhcnQub2YuU3RhdHVzLHVuaXRzPWMoImRheXMiKSkNCmBgYA0KSW4gd29tZW5zJyB2b2xsZXliYWxsIDI4IGxvd2VyIGJvZHkgaW5qdXJpZXMgb2NjdXJyZWQsIDQgb2YgdGhlbSBiZWluZyBBQ0wgaW5qdXJpZXMsIDEgb2YgdGhlbSBiZWluZyBIU0kgaW5qdXJpZXMuIA0KDQoyLiBEeW5hbW8gRGF0YXNldA0KDQojRHluYW1vIChWQUxEKSBCYXNrZXRiYWxsIERhdGENCmBgYHtyfQ0KI3NlbGVjdHMgdmFyaWFibGVzIG9mIGludGVyZXN0DQpkeW5hbW9fQiA8LSBzdWJzZXQoRHluYW1vX0IsIHNlbGVjdCA9IGMoJ2Fub25faWQnLCAnRGF0ZScsICdLbmVlLkV4LlJpZ2h0LlNpZGUuTWF4LkZvcmNlLi5OLicsICdLbmVlLkV4LkxlZnQuU2lkZS5NYXguRm9yY2UuLk4uJywgJ0tuZWUuRXguTWF4LkZvcmNlLi5OLi5Bc3ltbWV0cnknLCAnS25lZS5FeC5SaWdodC5TaWRlLkF2Zy5Gb3JjZS4uTi4nLCAnS25lZS5FeC5MZWZ0LlNpZGUuQXZnLkZvcmNlLi5OLicsICdLbmVlLkV4LkF2Zy5Gb3JjZS5Bc3ltbWV0cnknLCAnS25lZS5FeC5SaWdodC5TaWRlLk1heC5JbXB1bHNlLi5Ocy4nLCAnS25lZS5FeC5MZWZ0LlNpZGUuTWF4LkltcHVsc2UuLk5zLicsICdLbmVlLkV4Lk1heC5JbXB1bHNlLkFzeW1tZXRyeScsICdLbmVlLkV4LlJpZ2h0LlNpZGUuQXZnLkltcHVsc2UuLk5zLicsICdLbmVlLkV4LkxlZnQuU2lkZS5BdmcuSW1wdWxzZS4uTnMuJywgJ0tuZWUuRXguQXZnLkltcHVsc2UuQXN5bW1ldHJ5JywgJ0tuZWUuRXguUmlnaHQuU2lkZS5NYXguUmF0ZS5vZi5Gb3JjZS5EZXZlbG9wbWVudC4uTnMuJywgJ0tuZWUuRXguTGVmdC5TaWRlLk1heC5SYXRlLm9mLkZvcmNlLkRldmVsb3BtZW50Li5Ocy4nLCAnS25lZS5FeC5NYXguUmF0ZS5vZi5Gb3JjZS5EZXZlbG9wbWVudC5Bc3ltbWV0cnknLCAnS25lZS5FeC5SaWdodC5TaWRlLkF2Zy5SYXRlLm9mLkZvcmNlLkRldmVsb3BtZW50Li5Ocy4nLCAnS25lZS5FeC5MZWZ0LlNpZGUuQXZnLlJhdGUub2YuRm9yY2UuRGV2ZWxvcG1lbnQuLk5zLicsICdLbmVlLkV4LkF2Zy5SYXRlLm9mLkZvcmNlLkRldmVsb3BtZW50LkFzeW1tZXRyeScpKQ0KDQojY29udmVydHMgdGhlIGRhdGUgdG8gYSBkYXRlIG9iamVjdCBhbmQgb21pdHMgdGhlIE5BcyBhcyB3ZWxsIGFzIGNhbGN1bGF0aW5nIHRoZSBLbmVlLkV4Lk1heC5Gb3JjZS4uTi4uQXN5bW1ldHJ5IHZhcmlhYmxlIGZvciB0aGUgbWlzc2luZyB2YWx1ZXMNCmR5bmFtb19CIDwtIGR5bmFtb19CICU+JQ0KICBtdXRhdGUoRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0ID0gJyVtLyVkLyVZJyksDQogICAgICAgICBLbmVlLkV4Lk1heC5Gb3JjZS4uTi4uQXN5bW1ldHJ5ID0gY2FzZV93aGVuKA0KICAgICAgICAgICBLbmVlLkV4LkxlZnQuU2lkZS5NYXguRm9yY2UuLk4uID4gS25lZS5FeC5SaWdodC5TaWRlLk1heC5Gb3JjZS4uTi4gfiByb3VuZCgxMDAgKiAoMSAtIChLbmVlLkV4LlJpZ2h0LlNpZGUuTWF4LkZvcmNlLi5OLiAvIEtuZWUuRXguTGVmdC5TaWRlLk1heC5Gb3JjZS4uTi4pKSwgMSksDQogICAgICAgICAgIFRSVUUgfiBLbmVlLkV4Lk1heC5Gb3JjZS4uTi4uQXN5bW1ldHJ5DQogICAgICAgICApKSAlPiUNCiAgbmEub21pdCgpDQpgYGANCjE5IHRvdGFsIG9ic2VydmF0aW9ucywgMyB3aXRoIE5BIHZhbHVlcyBpbiBLbmVlLkV4Lk1heC5Gb3JjZS4uTi4uQXN5bW1ldHJ5Lg0KDQojRHluYW1vIChWQUxEKSBTb2NjZXIgRGF0YQ0KYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0NCiNzZWxlY3RzIHZhcmlhYmxlcyBvZiBpbnRlcmVzdA0KZHluYW1vX1MgPC0gc3Vic2V0KER5bmFtb19TLCBzZWxlY3QgPSBjKCdhbm9uX2lkJywgJ0RhdGUnLCAnS25lZS5FeC5SaWdodC5TaWRlLk1heC5Gb3JjZS4uTi4nLCAnS25lZS5FeC5MZWZ0LlNpZGUuTWF4LkZvcmNlLi5OLicsICdLbmVlLkV4Lk1heC5Gb3JjZS4uTi4uQXN5bW1ldHJ5JywgJ0tuZWUuRXguUmlnaHQuU2lkZS5BdmcuRm9yY2UuLk4uJywgJ0tuZWUuRXguTGVmdC5TaWRlLkF2Zy5Gb3JjZS4uTi4nLCAnS25lZS5FeC5BdmcuRm9yY2UuQXN5bW1ldHJ5JywgJ0tuZWUuRXguUmlnaHQuU2lkZS5NYXguSW1wdWxzZS4uTnMuJywgJ0tuZWUuRXguTGVmdC5TaWRlLk1heC5JbXB1bHNlLi5Ocy4nLCAnS25lZS5FeC5NYXguSW1wdWxzZS5Bc3ltbWV0cnknLCAnS25lZS5FeC5SaWdodC5TaWRlLkF2Zy5JbXB1bHNlLi5Ocy4nLCAnS25lZS5FeC5MZWZ0LlNpZGUuQXZnLkltcHVsc2UuLk5zLicsICdLbmVlLkV4LkF2Zy5JbXB1bHNlLkFzeW1tZXRyeScsICdLbmVlLkV4LlJpZ2h0LlNpZGUuTWF4LlJhdGUub2YuRm9yY2UuRGV2ZWxvcG1lbnQuLk5zLicsICdLbmVlLkV4LkxlZnQuU2lkZS5NYXguUmF0ZS5vZi5Gb3JjZS5EZXZlbG9wbWVudC4uTnMuJywgJ0tuZWUuRXguTWF4LlJhdGUub2YuRm9yY2UuRGV2ZWxvcG1lbnQuQXN5bW1ldHJ5JywgJ0tuZWUuRXguUmlnaHQuU2lkZS5BdmcuUmF0ZS5vZi5Gb3JjZS5EZXZlbG9wbWVudC4uTnMuJywgJ0tuZWUuRXguTGVmdC5TaWRlLkF2Zy5SYXRlLm9mLkZvcmNlLkRldmVsb3BtZW50Li5Ocy4nLCAnS25lZS5FeC5BdmcuUmF0ZS5vZi5Gb3JjZS5EZXZlbG9wbWVudC5Bc3ltbWV0cnknKSkNCg0KI2NvbnZlcnRzIHRoZSBkYXRlIHRvIGEgZGF0ZSBvYmplY3QgYW5kIHB1dHMgdmFsdWVzIGZyb20gZGlmZmVyZW50IG9ic2VydmF0aW9ucyB0b2dldGhlciBpbnRvIG9uZSBvYnNlcnZhdGlvbiwgdGhlbiBjYWxjdWxhdGVzIHRoZSBhc3ltbWV0cnkgc3RhdGlzdGljcw0KZHluYW1vX1MgPC0gZHluYW1vX1MgJT4lDQogIG11dGF0ZShEYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAnJW0vJWQvJVknKSkgJT4lDQogIGdyb3VwX2J5KGFub25faWQsIERhdGUpICU+JQ0KICBzdW1tYXJpc2UoS25lZS5FeC5SaWdodC5TaWRlLk1heC5Gb3JjZS4uTi4gPSBzdW0oS25lZS5FeC5SaWdodC5TaWRlLk1heC5Gb3JjZS4uTi4sIG5hLnJtID0gVFJVRSksIA0KICAgICAgICAgICAgS25lZS5FeC5MZWZ0LlNpZGUuTWF4LkZvcmNlLi5OLiA9IHN1bShLbmVlLkV4LkxlZnQuU2lkZS5NYXguRm9yY2UuLk4uLCBuYS5ybSA9IFRSVUUpLCANCiAgICAgICAgICAgIEtuZWUuRXguTWF4LkZvcmNlLi5OLi5Bc3ltbWV0cnkgPSBzdW0oS25lZS5FeC5NYXguRm9yY2UuLk4uLkFzeW1tZXRyeSksIA0KICAgICAgICAgICAgS25lZS5FeC5SaWdodC5TaWRlLkF2Zy5Gb3JjZS4uTi4gPSBzdW0oS25lZS5FeC5SaWdodC5TaWRlLkF2Zy5Gb3JjZS4uTi4sIG5hLnJtID0gVFJVRSksIA0KICAgICAgICAgICAgS25lZS5FeC5MZWZ0LlNpZGUuQXZnLkZvcmNlLi5OLiA9IHN1bShLbmVlLkV4LkxlZnQuU2lkZS5BdmcuRm9yY2UuLk4uLCBuYS5ybSA9IFRSVUUpLCANCiAgICAgICAgICAgIEtuZWUuRXguQXZnLkZvcmNlLkFzeW1tZXRyeSA9IHN1bShLbmVlLkV4LkF2Zy5Gb3JjZS5Bc3ltbWV0cnkpLCANCiAgICAgICAgICAgIEtuZWUuRXguUmlnaHQuU2lkZS5NYXguSW1wdWxzZS4uTnMuID0gc3VtKEtuZWUuRXguUmlnaHQuU2lkZS5NYXguSW1wdWxzZS4uTnMuLCBuYS5ybSA9IFRSVUUpLCANCiAgICAgICAgICAgIEtuZWUuRXguTGVmdC5TaWRlLk1heC5JbXB1bHNlLi5Ocy4gPSBzdW0oS25lZS5FeC5MZWZ0LlNpZGUuTWF4LkltcHVsc2UuLk5zLiwgbmEucm0gPSBUUlVFKSwgDQogICAgICAgICAgICBLbmVlLkV4Lk1heC5JbXB1bHNlLkFzeW1tZXRyeSA9IHN1bShLbmVlLkV4Lk1heC5JbXB1bHNlLkFzeW1tZXRyeSksIA0KICAgICAgICAgICAgS25lZS5FeC5SaWdodC5TaWRlLkF2Zy5JbXB1bHNlLi5Ocy4gPSBzdW0oS25lZS5FeC5SaWdodC5TaWRlLkF2Zy5JbXB1bHNlLi5Ocy4sIG5hLnJtID0gVFJVRSksIA0KICAgICAgICAgICAgS25lZS5FeC5MZWZ0LlNpZGUuQXZnLkltcHVsc2UuLk5zLiA9IHN1bShLbmVlLkV4LkxlZnQuU2lkZS5BdmcuSW1wdWxzZS4uTnMuLCBuYS5ybSA9IFRSVUUpLCANCiAgICAgICAgICAgIEtuZWUuRXguQXZnLkltcHVsc2UuQXN5bW1ldHJ5ID0gc3VtKEtuZWUuRXguQXZnLkltcHVsc2UuQXN5bW1ldHJ5KSwNCiAgICAgICAgICAgIEtuZWUuRXguUmlnaHQuU2lkZS5NYXguUmF0ZS5vZi5Gb3JjZS5EZXZlbG9wbWVudC4uTnMuID0gc3VtKEtuZWUuRXguUmlnaHQuU2lkZS5NYXguUmF0ZS5vZi5Gb3JjZS5EZXZlbG9wbWVudC4uTnMuLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgS25lZS5FeC5MZWZ0LlNpZGUuTWF4LlJhdGUub2YuRm9yY2UuRGV2ZWxvcG1lbnQuLk5zLiA9IHN1bShLbmVlLkV4LkxlZnQuU2lkZS5NYXguUmF0ZS5vZi5Gb3JjZS5EZXZlbG9wbWVudC4uTnMuLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgS25lZS5FeC5NYXguUmF0ZS5vZi5Gb3JjZS5EZXZlbG9wbWVudC5Bc3ltbWV0cnkgPSBzdW0oS25lZS5FeC5NYXguUmF0ZS5vZi5Gb3JjZS5EZXZlbG9wbWVudC5Bc3ltbWV0cnkpLA0KICAgICAgICAgICAgS25lZS5FeC5SaWdodC5TaWRlLkF2Zy5SYXRlLm9mLkZvcmNlLkRldmVsb3BtZW50Li5Ocy4gPSBzdW0oS25lZS5FeC5SaWdodC5TaWRlLkF2Zy5SYXRlLm9mLkZvcmNlLkRldmVsb3BtZW50Li5Ocy4sIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBLbmVlLkV4LkxlZnQuU2lkZS5BdmcuUmF0ZS5vZi5Gb3JjZS5EZXZlbG9wbWVudC4uTnMuID0gc3VtKEtuZWUuRXguTGVmdC5TaWRlLkF2Zy5SYXRlLm9mLkZvcmNlLkRldmVsb3BtZW50Li5Ocy4sIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBLbmVlLkV4LkF2Zy5SYXRlLm9mLkZvcmNlLkRldmVsb3BtZW50LkFzeW1tZXRyeSA9IHN1bShLbmVlLkV4LkF2Zy5SYXRlLm9mLkZvcmNlLkRldmVsb3BtZW50LkFzeW1tZXRyeSksIC5ncm91cHMgPSAiZHJvcCIpICU+JQ0KICBtdXRhdGUoS25lZS5FeC5NYXguRm9yY2UuLk4uLkFzeW1tZXRyeSA9IHJvdW5kKDEwMCAqICgxIC0gKEtuZWUuRXguTGVmdC5TaWRlLk1heC5Gb3JjZS4uTi4gLyBLbmVlLkV4LlJpZ2h0LlNpZGUuTWF4LkZvcmNlLi5OLikpLCAxKSwNCiAgICAgICAgIEtuZWUuRXguQXZnLkZvcmNlLkFzeW1tZXRyeSA9IHJvdW5kKDEwMCAqICgxIC0gKEtuZWUuRXguTGVmdC5TaWRlLkF2Zy5Gb3JjZS4uTi4gLyBLbmVlLkV4LlJpZ2h0LlNpZGUuQXZnLkZvcmNlLi5OLikpLCAxKSwNCiAgICAgICAgIEtuZWUuRXguTWF4LkltcHVsc2UuQXN5bW1ldHJ5ID0gcm91bmQoMTAwICogKDEgLSAoS25lZS5FeC5MZWZ0LlNpZGUuTWF4LkltcHVsc2UuLk5zLiAvIEtuZWUuRXguUmlnaHQuU2lkZS5NYXguSW1wdWxzZS4uTnMuKSksIDEpLA0KICAgICAgICAgS25lZS5FeC5BdmcuSW1wdWxzZS5Bc3ltbWV0cnkgPSByb3VuZCgxMDAgKiAoMSAtIChLbmVlLkV4LkxlZnQuU2lkZS5BdmcuSW1wdWxzZS4uTnMuIC8gS25lZS5FeC5SaWdodC5TaWRlLkF2Zy5JbXB1bHNlLi5Ocy4pKSwgMSksDQogICAgICAgICBLbmVlLkV4Lk1heC5SYXRlLm9mLkZvcmNlLkRldmVsb3BtZW50LkFzeW1tZXRyeSA9IHJvdW5kKDEwMCAqICgxIC0gKEtuZWUuRXguTGVmdC5TaWRlLk1heC5SYXRlLm9mLkZvcmNlLkRldmVsb3BtZW50Li5Ocy4gLyBLbmVlLkV4LlJpZ2h0LlNpZGUuTWF4LlJhdGUub2YuRm9yY2UuRGV2ZWxvcG1lbnQuLk5zLikpLCAxKSwNCiAgICAgICAgIEtuZWUuRXguQXZnLlJhdGUub2YuRm9yY2UuRGV2ZWxvcG1lbnQuQXN5bW1ldHJ5ID0gcm91bmQoMTAwICogKDEgLSAoS25lZS5FeC5MZWZ0LlNpZGUuQXZnLlJhdGUub2YuRm9yY2UuRGV2ZWxvcG1lbnQuLk5zLiAvIEtuZWUuRXguUmlnaHQuU2lkZS5BdmcuUmF0ZS5vZi5Gb3JjZS5EZXZlbG9wbWVudC4uTnMuKSksIDEpKQ0KYGBgDQpPbmx5IDEgb2JzZXJ2YXRpb24sIG5vbmUgb2YgdGhlIGFzeW1tZXRyeSBzdGF0aXN0aWNzIGFyZSBzdW1tYXJpemVkLiANCg0KI0R5bmFtbyAoVkFMRCkgTGFjcm9zc2UgRGF0YQ0KYGBge3J9DQojc2VsZWN0cyB2YXJpYWJsZXMgb2YgaW50ZXJlc3QNCmR5bmFtb19MIDwtIHN1YnNldChEeW5hbW9fTCwgc2VsZWN0ID0gYygnYW5vbl9pZCcsICdEYXRlJywgJ0tuZWUuRXguUmlnaHQuU2lkZS5NYXguRm9yY2UuLk4uJywgJ0tuZWUuRXguTGVmdC5TaWRlLk1heC5Gb3JjZS4uTi4nLCAnS25lZS5FeC5NYXguRm9yY2UuLk4uLkFzeW1tZXRyeScsICdLbmVlLkV4LlJpZ2h0LlNpZGUuQXZnLkZvcmNlLi5OLicsICdLbmVlLkV4LkxlZnQuU2lkZS5BdmcuRm9yY2UuLk4uJywgJ0tuZWUuRXguQXZnLkZvcmNlLkFzeW1tZXRyeScsICdLbmVlLkV4LlJpZ2h0LlNpZGUuTWF4LkltcHVsc2UuLk5zLicsICdLbmVlLkV4LkxlZnQuU2lkZS5NYXguSW1wdWxzZS4uTnMuJywgJ0tuZWUuRXguTWF4LkltcHVsc2UuQXN5bW1ldHJ5JywgJ0tuZWUuRXguUmlnaHQuU2lkZS5BdmcuSW1wdWxzZS4uTnMuJywgJ0tuZWUuRXguTGVmdC5TaWRlLkF2Zy5JbXB1bHNlLi5Ocy4nLCAnS25lZS5FeC5BdmcuSW1wdWxzZS5Bc3ltbWV0cnknLCAnS25lZS5FeC5SaWdodC5TaWRlLk1heC5SYXRlLm9mLkZvcmNlLkRldmVsb3BtZW50Li5Ocy4nLCAnS25lZS5FeC5MZWZ0LlNpZGUuTWF4LlJhdGUub2YuRm9yY2UuRGV2ZWxvcG1lbnQuLk5zLicsICdLbmVlLkV4Lk1heC5SYXRlLm9mLkZvcmNlLkRldmVsb3BtZW50LkFzeW1tZXRyeScsICdLbmVlLkV4LlJpZ2h0LlNpZGUuQXZnLlJhdGUub2YuRm9yY2UuRGV2ZWxvcG1lbnQuLk5zLicsICdLbmVlLkV4LkxlZnQuU2lkZS5BdmcuUmF0ZS5vZi5Gb3JjZS5EZXZlbG9wbWVudC4uTnMuJywgJ0tuZWUuRXguQXZnLlJhdGUub2YuRm9yY2UuRGV2ZWxvcG1lbnQuQXN5bW1ldHJ5JykpDQoNCiNjb252ZXJ0cyB0aGUgZGF0ZSB0byBhIGRhdGUgb2JqZWN0IGFuZCBvbWl0cyB0aGUgTkFzIGFzIHdlbGwgYXMgY2FsY3VsYXRpbmcgdGhlIEtuZWUuRXguTWF4LkZvcmNlLi5OLi5Bc3ltbWV0cnkgdmFyaWFibGUgZm9yIHRoZSBtaXNzaW5nIHZhbHVlcw0KZHluYW1vX0wgPC0gZHluYW1vX0wgJT4lDQogIG11dGF0ZShEYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAnJW0vJWQvJVknKSwNCiAgICAgICAgIEtuZWUuRXguTWF4LkZvcmNlLi5OLi5Bc3ltbWV0cnkgPSBjYXNlX3doZW4oDQogICAgICAgICAgIEtuZWUuRXguTGVmdC5TaWRlLk1heC5Gb3JjZS4uTi4gPiBLbmVlLkV4LlJpZ2h0LlNpZGUuTWF4LkZvcmNlLi5OLiB+IHJvdW5kKDEwMCAqICgxIC0gKEtuZWUuRXguUmlnaHQuU2lkZS5NYXguRm9yY2UuLk4uIC8gS25lZS5FeC5MZWZ0LlNpZGUuTWF4LkZvcmNlLi5OLikpLCAxKSwNCiAgICAgICAgICAgVFJVRSB+IEtuZWUuRXguTWF4LkZvcmNlLi5OLi5Bc3ltbWV0cnkNCiAgICAgICAgICkpICU+JQ0KICBuYS5vbWl0KCkNCmBgYA0KMzggdG90YWwgb2JzZXJ2YXRpb25zLCAyMyB3aXRoIE5BIHZhbHVlcyBpbiBLbmVlLkV4Lk1heC5Gb3JjZS4uTi4uQXN5bW1ldHJ5Lg0KDQojRHluYW1vIChWQUxEKSBWb2xsZXliYWxsIERhdGENCmBgYHtyfQ0KI3NlbGVjdHMgdmFyaWFibGVzIG9mIGludGVyZXN0DQpkeW5hbW9fViA8LSBzdWJzZXQoRHluYW1vX1YsIHNlbGVjdCA9IGMoJ2Fub25faWQnLCAnRGF0ZScsICdLbmVlLkV4LlJpZ2h0LlNpZGUuTWF4LkZvcmNlLi5OLicsICdLbmVlLkV4LkxlZnQuU2lkZS5NYXguRm9yY2UuLk4uJywgJ0tuZWUuRXguTWF4LkZvcmNlLi5OLi5Bc3ltbWV0cnknLCAnS25lZS5FeC5SaWdodC5TaWRlLkF2Zy5Gb3JjZS4uTi4nLCAnS25lZS5FeC5MZWZ0LlNpZGUuQXZnLkZvcmNlLi5OLicsICdLbmVlLkV4LkF2Zy5Gb3JjZS5Bc3ltbWV0cnknLCAnS25lZS5FeC5SaWdodC5TaWRlLk1heC5JbXB1bHNlLi5Ocy4nLCAnS25lZS5FeC5MZWZ0LlNpZGUuTWF4LkltcHVsc2UuLk5zLicsICdLbmVlLkV4Lk1heC5JbXB1bHNlLkFzeW1tZXRyeScsICdLbmVlLkV4LlJpZ2h0LlNpZGUuQXZnLkltcHVsc2UuLk5zLicsICdLbmVlLkV4LkxlZnQuU2lkZS5BdmcuSW1wdWxzZS4uTnMuJywgJ0tuZWUuRXguQXZnLkltcHVsc2UuQXN5bW1ldHJ5JywgJ0tuZWUuRXguUmlnaHQuU2lkZS5NYXguUmF0ZS5vZi5Gb3JjZS5EZXZlbG9wbWVudC4uTnMuJywgJ0tuZWUuRXguTGVmdC5TaWRlLk1heC5SYXRlLm9mLkZvcmNlLkRldmVsb3BtZW50Li5Ocy4nLCAnS25lZS5FeC5NYXguUmF0ZS5vZi5Gb3JjZS5EZXZlbG9wbWVudC5Bc3ltbWV0cnknLCAnS25lZS5FeC5SaWdodC5TaWRlLkF2Zy5SYXRlLm9mLkZvcmNlLkRldmVsb3BtZW50Li5Ocy4nLCAnS25lZS5FeC5MZWZ0LlNpZGUuQXZnLlJhdGUub2YuRm9yY2UuRGV2ZWxvcG1lbnQuLk5zLicsICdLbmVlLkV4LkF2Zy5SYXRlLm9mLkZvcmNlLkRldmVsb3BtZW50LkFzeW1tZXRyeScpKQ0KDQojY29udmVydHMgdGhlIGRhdGUgdG8gYSBkYXRlIG9iamVjdCBhbmQgb21pdHMgdGhlIE5BcyBhcyB3ZWxsIGFzIGNhbGN1bGF0aW5nIHRoZSBLbmVlLkV4Lk1heC5Gb3JjZS4uTi4uQXN5bW1ldHJ5IHZhcmlhYmxlIGZvciB0aGUgbWlzc2luZyB2YWx1ZXMNCmR5bmFtb19WIDwtIGR5bmFtb19WICU+JQ0KICBtdXRhdGUoRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0ID0gJyVtLyVkLyVZJyksDQogICAgICAgICBLbmVlLkV4Lk1heC5Gb3JjZS4uTi4uQXN5bW1ldHJ5ID0gY2FzZV93aGVuKA0KICAgICAgICAgICBLbmVlLkV4LkxlZnQuU2lkZS5NYXguRm9yY2UuLk4uID4gS25lZS5FeC5SaWdodC5TaWRlLk1heC5Gb3JjZS4uTi4gfiByb3VuZCgxMDAgKiAoMSAtIChLbmVlLkV4LlJpZ2h0LlNpZGUuTWF4LkZvcmNlLi5OLiAvIEtuZWUuRXguTGVmdC5TaWRlLk1heC5Gb3JjZS4uTi4pKSwgMSksDQogICAgICAgICAgIFRSVUUgfiBLbmVlLkV4Lk1heC5Gb3JjZS4uTi4uQXN5bW1ldHJ5DQogICAgICAgICApKSAlPiUNCiAgbmEub21pdCgpDQpgYGANCk9ubHkgaGFzIDQgb2JzZXJ2YXRpb25zIGZyb20gb25lIHBsYXllci4NCg0KMy4gVkFMRC0gRm9yY2VkZWNrcyBkYXRhc2V0cw0KI0ZvcmNlZGVja3MgKFZBTEQpIGJhc2tldGJhbGwgZGF0YQ0KYGBge3J9DQojMTogVEVTVCBUWVBFPUNNSg0KQ01KX0IgPC0gc3Vic2V0KEZvcmNlZGVja3NfQiwgc2VsZWN0ID0gYygiYW5vbl9pZCIsIkRhdGUiLCJQb3NpdGlvbiIsIlRlc3QuVHlwZSIsIldlaWdodC4ua2cuIiwiQ291bnRlcm1vdmVtZW50LkRlcHRoLi5jbS4iLCJQZWFrLlBvd2VyLi4uQk0uLlcua2cuIiwiTGFuZGluZy5SRkQuLk4ucy4iLCAiRWNjZW50cmljLkNvbmNlbnRyaWMuTWVhbi5Gb3JjZS5SYXRpbyIsICJQZWFrLkxhbmRpbmcuRm9yY2UuLkFzeW0uLi5OLiIsICJQZWFrLlBvd2VyLi5XLiIsIkNvbmNlbnRyaWMuTWF4aW11bS5SRkQuLk4ucy4iLCJDb25jZW50cmljLk1heGltdW0uUkZELi5SaWdodC4uLk4ucy4iLCJDb25jZW50cmljLk1heGltdW0uUkZELi5MZWZ0Li4uTi5zLiIsIkVjY2VudHJpYy5NZWFuLkJyYWtpbmcuRm9yY2UuLk4uIiwgIk1heC5KdW1wLkhlaWdodC4uY20uIiwgIk1heC5Db25jZW50cmljLlBlYWsuRm9yY2UuLk4uIiwgIlJlbGF0aXZlLkNvbmNlbnRyaWMuUG93ZXIuQmlsYXRlcmFsIiwiUmVsYXRpdmUuRWNjZW50cmljLlBvd2VyLkJpbGF0ZXJhbCIsICJNYXguUGVhay5Qb3dlci4uLkJNIiwgIk1heC5FY2NlbnRyaWMuUGVhay5Gb3JjZS4uTi4iLCJNYXguUlNJLk1vZGlmaWVkLlZBTEQiLCJNYXguQ29uY2VudHJpYy5SUEQuLk4ucy4iLCJNYXguQ29uY2VudHJpYy5QZWFrLlZlbG9jaXR5Li5tLnMuIiwgIk1heC5FY2NlbnRyaWMuUGVhay5WZWxvY2l0eS4ubS5zLiIsICJNYXguUGVhay5MYW5kaW5nLkZvcmNlLi5OLiIsICJNQVguQ29uY2VudHJpYy5QZWFrLlBvd2VyLi5XLiIsICJNYXguQ01KLkp1bXAuSGVpZ2h0Li5jbS4iLCJNYXguQ01KLlJTSS5Nb2RpZmllZC4ubS5zLiIsICJNYXguQ01KLkNvbmNlbnRyaWMuUlBELi5OLnMuIiwgIk1heC5DTUouUGVhay5Qb3dlci4uVy4iLCAiTWF4LkNNSi5QZWFrLkxhbmRpbmcuRm9yY2UuLk4uIiwiQ01KLkNvbmNlbnRyaWMuUmVsYXRpdmUuUGVhay5Qb3dlci4uLkRpZmZlcmVuY2UuZnJvbS5GaXJzdCIsIkNNSi5FY2NlbnRyaWMuUmVsYXRpdmUuUGVhay5Qb3dlci4uLkRpZmZlcmVuY2UuZnJvbS5GaXJzdCIsIkVjY2VudHJpYy5Bc3ltbWV0cnkiLCJDb25jZW50cmljLkFzeW1tZXRyeSINCikpICAgICAgICAgICAgIzI3NTEgb2JzICYgMzYgdmFycy4NCg0KI3Bvc3NpYmxlIG90aGVyIGZpbmFsIGRhdGFzZXQgDQpjbWpfYiA8LSBDTUpfQiAlPiUNCiAgbmEub21pdCgpICAgIzQ0MCBvYnMNCg0KI2NvbnZlcnQgZW1wdHkgdmVjdG9ycyB0byBOQQ0KQ01KX0JbQ01KX0I9PSIiXSA8LSBOQSAgICAjY29sU3Vtcyhpcy5uYShmb3JjZWRlY2tzX0IpKSBsb29rIGF0IE5BcyBpbiBjb2x1bW5zDQoNCiN0byB1c2UgaW4gc3VtbWFyaXNlDQojZnVuY3Rpb24gZm9yIG1vZGUNCmdldF9tb2RlIDwtIGZ1bmN0aW9uKHYpIHsNCiAgdW5pcXYgPC0gdW5pcXVlKHYpDQogIHVuaXF2W3doaWNoLm1heCh0YWJ1bGF0ZShtYXRjaCh2LCB1bmlxdikpKV0NCn0NCg0KI3NldCBhbGwgbmVlZGVkIHZhcmlhYmxlcyB0byBudW1lcmljDQpDTUpfQiRDb3VudGVybW92ZW1lbnQuRGVwdGguLmNtLiA8LSBhcy5udW1lcmljKENNSl9CJENvdW50ZXJtb3ZlbWVudC5EZXB0aC4uY20uKQ0KQ01KX0IkUGVhay5Qb3dlci4uLkJNLi5XLmtnLiA8LSBhcy5udW1lcmljKENNSl9CJFBlYWsuUG93ZXIuLi5CTS4uVy5rZy4pDQoNCiNjb21iaW5pbmcgdmFsdWVzIGZyb20gZGlmZmVyZW50IG9ic2VydmF0aW9ucyBpbnRvIG9uZQ0KQ01KX2IgPC0gQ01KX0IgJT4lDQptdXRhdGUoRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0ID0gJyVtLyVkLyVZJykpICU+JQ0KICBncm91cF9ieShhbm9uX2lkLCBEYXRlLFRlc3QuVHlwZSkgJT4lDQogIHN1bW1hcmlzZShXZWlnaHQuLmtnLiA9IG1lYW4oV2VpZ2h0Li5rZy4sIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBDb3VudGVybW92ZW1lbnQuRGVwdGguLmNtLj0gbWVhbihDb3VudGVybW92ZW1lbnQuRGVwdGguLmNtLiwgbmEucm09VFJVRSksDQogICAgICAgICAgICBQZWFrLlBvd2VyLi4uQk0uLlcua2cuPSBtZWFuKFBlYWsuUG93ZXIuLi5CTS4uVy5rZy4sIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTGFuZGluZy5SRkQuLk4ucy49IG1lYW4oTGFuZGluZy5SRkQuLk4ucy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBFY2NlbnRyaWMuQ29uY2VudHJpYy5NZWFuLkZvcmNlLlJhdGlvPSBtZWFuKEVjY2VudHJpYy5Db25jZW50cmljLk1lYW4uRm9yY2UuUmF0aW8sbmEucm09VFJVRSksDQogICAgICAgICAgICBQZWFrLkxhbmRpbmcuRm9yY2UuLkFzeW0uLi5OLj0gbWVhbihQZWFrLkxhbmRpbmcuRm9yY2UuLkFzeW0uLi5OLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIFBlYWsuUG93ZXIuLlcuPSBtZWFuKFBlYWsuUG93ZXIuLlcuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgQ29uY2VudHJpYy5NYXhpbXVtLlJGRC4uTi5zLj0gbWVhbihDb25jZW50cmljLk1heGltdW0uUkZELi5OLnMuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgQ29uY2VudHJpYy5NYXhpbXVtLlJGRC4uUmlnaHQuLi5OLnMuPSBtZWFuKENvbmNlbnRyaWMuTWF4aW11bS5SRkQuLlJpZ2h0Li4uTi5zLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIENvbmNlbnRyaWMuTWF4aW11bS5SRkQuLkxlZnQuLi5OLnMuPSBtZWFuKENvbmNlbnRyaWMuTWF4aW11bS5SRkQuLkxlZnQuLi5OLnMuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgRWNjZW50cmljLk1lYW4uQnJha2luZy5Gb3JjZS4uTi49IG1lYW4oRWNjZW50cmljLk1lYW4uQnJha2luZy5Gb3JjZS4uTi4sbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguSnVtcC5IZWlnaHQuLmNtLj0gbWVhbihNYXguSnVtcC5IZWlnaHQuLmNtLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5Db25jZW50cmljLlBlYWsuRm9yY2UuLk4uPSBtZWFuKE1heC5Db25jZW50cmljLlBlYWsuRm9yY2UuLk4uLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgUmVsYXRpdmUuQ29uY2VudHJpYy5Qb3dlci5CaWxhdGVyYWw9IG1lYW4oUmVsYXRpdmUuQ29uY2VudHJpYy5Qb3dlci5CaWxhdGVyYWwsbmEucm09VFJVRSksDQogICAgICAgICAgICBSZWxhdGl2ZS5FY2NlbnRyaWMuUG93ZXIuQmlsYXRlcmFsPSBtZWFuKFJlbGF0aXZlLkVjY2VudHJpYy5Qb3dlci5CaWxhdGVyYWwsbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguUGVhay5Qb3dlci4uLkJNPSBtZWFuKE1heC5QZWFrLlBvd2VyLi4uQk0sbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguRWNjZW50cmljLlBlYWsuRm9yY2UuLk4uPSBtZWFuKE1heC5FY2NlbnRyaWMuUGVhay5Gb3JjZS4uTi4sbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguUlNJLk1vZGlmaWVkLlZBTEQ9IG1lYW4oTWF4LlJTSS5Nb2RpZmllZC5WQUxELG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkNvbmNlbnRyaWMuUlBELi5OLnMuPSBtZWFuKE1heC5Db25jZW50cmljLlJQRC4uTi5zLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5Db25jZW50cmljLlBlYWsuVmVsb2NpdHkuLm0ucy49IG1lYW4oTWF4LkNvbmNlbnRyaWMuUGVhay5WZWxvY2l0eS4ubS5zLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5FY2NlbnRyaWMuUGVhay5WZWxvY2l0eS4ubS5zLj0gbWVhbihNYXguRWNjZW50cmljLlBlYWsuVmVsb2NpdHkuLm0ucy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguUGVhay5MYW5kaW5nLkZvcmNlLi5OLj0gbWVhbihNYXguUGVhay5MYW5kaW5nLkZvcmNlLi5OLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1BWC5Db25jZW50cmljLlBlYWsuUG93ZXIuLlcuPSBtZWFuKE1BWC5Db25jZW50cmljLlBlYWsuUG93ZXIuLlcuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkNNSi5KdW1wLkhlaWdodC4uY20uPSBtZWFuKE1heC5DTUouSnVtcC5IZWlnaHQuLmNtLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5DTUouUlNJLk1vZGlmaWVkLi5tLnMuPSBtZWFuKE1heC5DTUouUlNJLk1vZGlmaWVkLi5tLnMuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkNNSi5Db25jZW50cmljLlJQRC4uTi5zLj0gbWVhbihNYXguQ01KLkNvbmNlbnRyaWMuUlBELi5OLnMuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkNNSi5QZWFrLlBvd2VyLi5XLj0gbWVhbihNYXguQ01KLlBlYWsuUG93ZXIuLlcuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkNNSi5QZWFrLkxhbmRpbmcuRm9yY2UuLk4uPSBtZWFuKE1heC5DTUouUGVhay5MYW5kaW5nLkZvcmNlLi5OLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIENNSi5Db25jZW50cmljLlJlbGF0aXZlLlBlYWsuUG93ZXIuLi5EaWZmZXJlbmNlLmZyb20uRmlyc3Q9IG1lYW4oQ01KLkNvbmNlbnRyaWMuUmVsYXRpdmUuUGVhay5Qb3dlci4uLkRpZmZlcmVuY2UuZnJvbS5GaXJzdCxuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIENNSi5FY2NlbnRyaWMuUmVsYXRpdmUuUGVhay5Qb3dlci4uLkRpZmZlcmVuY2UuZnJvbS5GaXJzdD0gbWVhbihDTUouRWNjZW50cmljLlJlbGF0aXZlLlBlYWsuUG93ZXIuLi5EaWZmZXJlbmNlLmZyb20uRmlyc3QsbmEucm09VFJVRSksDQogICAgICAgICAgICBQb3NpdGlvbj0gZ2V0X21vZGUoUG9zaXRpb24pLA0KICAgICAgICAgICAgRWNjZW50cmljLkFzeW1tZXRyeT0gZ2V0X21vZGUoRWNjZW50cmljLkFzeW1tZXRyeSksDQogICAgICAgICAgICBDb25jZW50cmljLkFzeW1tZXRyeT0gZ2V0X21vZGUoQ29uY2VudHJpYy5Bc3ltbWV0cnkpLA0KICAgICAgICAgICAgLmdyb3VwcyA9ICdkcm9wJw0KICAgICAgICAgICAgICApICAgICAgICAgICAgICAgICAgICMxMzkzIG9icyAmIDM2IHZhcnMNCiNmaXggTmFOIHZhbHVlcw0KDQpDTUpfYmIgPC0gQ01KX2IgJT4lDQogIG5hLm9taXQoKSAgICMxOTYgb2JzICYgMzYgdmFycw0KYGBgDQoNCmBgYHtyfQ0KI3NlbGVjdHMgY291bnRlciBtb3ZlbWVudCBqdW1wcyBhbm90aGVyIHdheSB3aXRoIG5vcm1hdGl2ZSBpbmZvcm1hdGlvbg0KYiA8LSBGb3JjZWRlY2tzX0IgJT4lDQogIGZpbHRlcihUZXN0LlR5cGUgPT0gJ0NNSicpICU+JQ0KICBkcGx5cjo6c2VsZWN0KCJhbm9uX2lkIiwiRGF0ZSIsIlBvc2l0aW9uIiwiVGVzdC5UeXBlIiwiQ291bnRlcm1vdmVtZW50LkRlcHRoLi5jbS4iLCJQZWFrLlBvd2VyLi4uQk0uLlcua2cuIiwiTGFuZGluZy5SRkQuLk4ucy4iLCAiRWNjZW50cmljLkNvbmNlbnRyaWMuTWVhbi5Gb3JjZS5SYXRpbyIsICJQZWFrLkxhbmRpbmcuRm9yY2UuLkFzeW0uLi5OLiIsICJQZWFrLlBvd2VyLi5XLiIsICJDb25jZW50cmljLlJGRC4uTi5zLiIsICJDb25jZW50cmljLlJGRC4uTGVmdC4uLk4ucy4iLCJDb25jZW50cmljLlJGRC4uUmlnaHQuLi5OLnMuIiwgIkNvbmNlbnRyaWMuVGltZS50by5QZWFrLkZvcmNlLi5zLiIsICJFY2NlbnRyaWMuTWVhbi5CcmFraW5nLkZvcmNlLi5OLiIsICJMYW5kaW5nLk5ldC5QZWFrLkZvcmNlLi4uQk0uLk4ua2cuIiwgIlBlYWsuTmV0LlRha2VvZmYuRm9yY2UuLi5CTS4uTi5rZy4iLCAiQ29uY2VudHJpYy5SUEQuLi5CTS4uVy5zLmtnLiIsICJGb3JjZS5hdC5QZWFrLlBvd2VyLi5OLiIsICJFY2NlbnRyaWMuTWVhbi5EZWNlbGVyYXRpb24uRm9yY2UuLk4uIiwgIkVjY2VudHJpYy5QZWFrLkZvcmNlLi5OLiIsICJSU0kuTW9kaWZpZWQuLm0ucy4iLCAiQ01KLlN0aWZmbmVzcy4uTGVmdC4uLk4ubS4iLCAiQ01KLlN0aWZmbmVzcy4uUmlnaHQuLi5OLm0uIiwgIkVjY2VudHJpYy5Bc3ltbWV0cnkiLCJDb25jZW50cmljLkFzeW1tZXRyeSIsICJQZWFrLkxhbmRpbmcuQXN5bW1ldHJ5IiwgIkRTSSIsICJEU0kuQnVja2V0IiwgIkVjY2VudHJpYy5QZWFrLlBvd2VyLi4uQk0uLlcua2cuIiwgIkp1bXAuSGVpZ2h0Li5JbXAuTW9tLi4uY20uIiwgIkVjY2VudHJpYy5EdXJhdGlvbi4ucy4iLCAiRWNjZW50cmljLkRlY2VsZXJhdGlvbi5JbXB1bHNlLi5Ocy4iKSAlPiUNCiAgbmEub21pdCgpDQoNCiNjYWxjdWxhdGVzIGRpZmZlcmVuY2VzIGZyb20gbm9ybSBhbmQgbWFrZXMgRGF0ZSBhIGRhdGUgb2JqZWN0DQpiIDwtIGIgJT4lDQogIG11dGF0ZShEYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAnJW0vJWQvJVknKSwNCiAgICAgICAgIFJTSS5Nb2RpZmllZC4ubS5zLiA9IFJTSS5Nb2RpZmllZC4ubS5zLiAvIDEwMCwNCiAgICAgICAgIFJTSS5Nb2RpZmllZC5EaWZmLk5vcm0gPSAoUlNJLk1vZGlmaWVkLi5tLnMuIC0gMC40MTcpIC8gMC40MTcsDQogICAgICAgICBFY2MuUGVhay5Qb3dlci5SZWwuRGlmZi5Ob3JtID0gKEVjY2VudHJpYy5QZWFrLlBvd2VyLi4uQk0uLlcua2cuIC0gMTgpIC8gMTgsDQogICAgICAgICBKdW1wLkhlaWdoLkRpZmYuTm9ybSA9IChKdW1wLkhlaWdodC4uSW1wLk1vbS4uLmNtLiAtIDMwKSAvIDMwLA0KICAgICAgICAgRWNjLkR1cmF0aW9uLkRpZmYuTm9ybSA9IChFY2NlbnRyaWMuRHVyYXRpb24uLnMuIC0gMC41MSkgLyAwLjUxLA0KICAgICAgICAgRWNjLkRlY2VsZXJhdGlvbi5JbXB1bHNlLkRpZmYuTm9ybSA9IChFY2NlbnRyaWMuRGVjZWxlcmF0aW9uLkltcHVsc2UuLk5zLiAtIDk4LjQpIC8gOTguNCwNCiAgICAgICAgIFNwb3J0ID0gJ0Jhc2tldGJhbGwnDQogICkgIzQ0MiBvYnMgYW5kIDM5IHZhcnMNCmBgYA0KDQpgYGB7cn0NCiMyIFRFU1QgVFlQRT1ISg0KSEpfQiA8LSBGb3JjZWRlY2tzX0IgJT4lDQogIGZpbHRlcihUZXN0LlR5cGU9PSJISiIpICAlPiUgIzQyNCBvYnMNCiAgZHBseXI6OnNlbGVjdCgiYW5vbl9pZCIsICJEYXRlIiwgIkNvcnJlY3RlZC5TdGFuZGluZy5XZWlnaHQuLktnLiIsICJNZWFuLlJTSS4uRmxpZ2h0LkNvbnRhY3QuVGltZS4iLCAiQWN0aXZlLlN0aWZmbmVzcy4uTi5tLiIsICJCZXN0LkF2ZXJhZ2UuRm9yY2UuLk4uIiwgIkJlc3QuQXZlcmFnZS5Gb3JjZS4uQXN5bS4uLk4uIiwgIkJlc3QuVGltZS50by5QZWFrLkZvcmNlLi5tcy4iLCAiQmVzdC5Db250YWN0LlRpbWUuLm1zLiIsICJCZXN0LkZsaWdodC5UaW1lLi5tcy4iLCAiQmVzdC5JbXB1bHNlLi5OLnMuIiwgIkJlc3QuUGVhay5Gb3JjZS4uTi4iLCAiQmVzdC5QZWFrLkZvcmNlLi5Bc3ltLi4uTi4iLCAiTWVhbi5BdmVyYWdlLkZvcmNlLi5OLiIsICJNZWFuLkF2ZXJhZ2UuRm9yY2UuLkFzeW0uLi5OLiIsICJNZWFuLkxhbmRpbmcuUkZELi5OLnMuIiwgIk1lYW4uTGFuZGluZy5SRkQuLkFzeW0uLi5OLnMuIiwgIlN0aWZmbmVzcy5GYXRpZ3VlLi4uLiIsICJTdGlmZm5lc3MuRmF0aWd1ZS4uQXN5bS4uLi4uIiwgIk1heC5KdW1wLkhlaWdodC4uY20uIiwgIkhKLlJTSSIsICJNZWFuLkZsaWdodC5UaW1lLi5tcy4iLCAiTWVhbi5Db250YWN0LlRpbWUuLm1zLiIpICU+JQ0KICBtdXRhdGUoRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0ID0gJyVtLyVkLyVZJykpICU+JQ0KICBuYS5vbWl0KCkgJT4lDQogIG11dGF0ZShTcG9ydCA9ICdCYXNrZXRiYWxsJykNCiAgICAgICAgICAgICAgICAgIzQwOSBvYnMgJiAyMCB2YXJzDQpgYGANCg0KYGBge3J9DQojMzogVEVTVCBUWVBFPSBJTVRQDQpJTVRQX0IgPC0gRm9yY2VkZWNrc19CICU+JQ0KICBmaWx0ZXIoVGVzdC5UeXBlPT0iSU1UUCIpICU+JSAjMTYyIA0KICBzZWxlY3QoImFub25faWQiLCAiRGF0ZSIsICJCYXNlbGluZS5Gb3JjZS4uTi4iLCJCYXNlbGluZS5Gb3JjZS4uQXN5bS4uLk4uIiwgIlBlYWsuVmVydGljYWwuRm9yY2UuLk4uIiwgIlBlYWsuVmVydGljYWwuRm9yY2UuLi5CTS4uTi5rZy4iLCAiUGVhay5WZXJ0aWNhbC5Gb3JjZS4uQXN5bS4uLk4uIiwgIlJGRC4uLjUwbXMuLk4ucy4iLCAiUkZELi4uNTBtcy4uQXN5bS4uLk4ucy4iLCAiUkZELi4uMTAwbXMuLk4ucy4iLCAiUkZELi4uMTAwbXMuLkFzeW0uLi5OLnMuIiwgIlJGRC4uLjE1MG1zLi5OLnMuIiwgIlJGRC4uLjE1MG1zLi5Bc3ltLi4uTi5zLiIsICJSRkQuLi4yMDBtcy4uTi5zLiIsICJSRkQuLi4yMDBtcy4uQXN5bS4uLk4ucy4iLCAiTmV0LlBlYWsuVmVydGljYWwuRm9yY2UuLk4ucy4iLCAiTmV0LlBlYWsuVmVydGljYWwuRm9yY2UuLkFzeW0uLi5OLnMuIiwgIkZvcmNlLmF0LjIwMG1zLi4uQk0uLk4ua2cuIiwgIkVjY2VudHJpYy5Bc3ltbWV0cnkiLCAiQ29uY2VudHJpYy5Bc3ltbWV0cnkiLCJNRUFOLkVjY2VudHJpYy5NZWFuLkZvcmNlLkxlZnQiLCAiTUVBTi5FY2NlbnRyaWMuTWVhbi5Gb3JjZS5SaWdodCIsICJNRUFOLkNvbmNlbnRyaWMuTWVhbi5Gb3JjZS5MZWZ0IiwgIk1FQU4uQ29uY2VudHJpYy5NZWFuLkZvcmNlLlJpZ2h0IiwgIk1FQU4uQ29uY2VudHJpYy5NZWFuLkZvcmNlLkFzeW0iLCAiTUVBTi5QZWFrLkxhbmRpbmcuRm9yY2UuQXN5bSIsICAiTUVBTi5SZWxhdGl2ZS5QZWFrLlBvd2VyIiwgIk1FQU4uQ01KLkNvbmNlbnRyaWMuRm9yY2UiLCAiTUVBTi5QZWFrLkxhbmRpbmcuRm9yY2UuTGVmdCIsICJNRUFOLlBlYWsuTGFuZGluZy5Gb3JjZS5SaWdodCIsICJEU0kiLCAiRFNJLkJ1Y2tldCIpICU+JQ0KICBtdXRhdGUoRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0ID0gJyVtLyVkLyVZJykpICU+JQ0KICBuYS5vbWl0KCkgJT4lDQogIG11dGF0ZShTcG9ydCA9ICdCYXNrZXRiYWxsJykgICM1MCBvYnMgJiAzMiB2YXJzDQpgYGANCg0KI0ZvcmNlZGVja3MgKFZBTEQpIFNvY2NlciBEYXRhDQpgYGB7cn0NCiMxOiBURVNUIFRZUEU9PUNNSg0KI3NlbGVjdHMgdmFyaWFibGVzIG9mIGludGVyZXN0DQpDTUpfUyA8LSBzdWJzZXQoRm9yY2VkZWNrc19TLCBzZWxlY3QgPSBjKCJhbm9uX2lkIiwiRGF0ZSIsIlBvc2l0aW9uIiwiVGVzdC5UeXBlIiwiV2VpZ2h0Li5rZy4iLCJDb3VudGVybW92ZW1lbnQuRGVwdGguLmNtLiIsIlBlYWsuUG93ZXIuLi5CTS4uVy5rZy4iLCJMYW5kaW5nLlJGRC4uTi5zLiIsICJFY2NlbnRyaWMuQ29uY2VudHJpYy5NZWFuLkZvcmNlLlJhdGlvIiwgIlBlYWsuTGFuZGluZy5Gb3JjZS4uQXN5bS4uLk4uIiwgIlBlYWsuUG93ZXIuLlcuIiwiQ29uY2VudHJpYy5NYXhpbXVtLlJGRC4uTi5zLiIsIkNvbmNlbnRyaWMuTWF4aW11bS5SRkQuLlJpZ2h0Li4uTi5zLiIsIkNvbmNlbnRyaWMuTWF4aW11bS5SRkQuLkxlZnQuLi5OLnMuIiwiRWNjZW50cmljLk1lYW4uQnJha2luZy5Gb3JjZS4uTi4iLCAiTWF4Lkp1bXAuSGVpZ2h0Li5jbS4iLCAiTWF4LkNvbmNlbnRyaWMuUGVhay5Gb3JjZS4uTi4iLCAiUmVsYXRpdmUuQ29uY2VudHJpYy5Qb3dlci5CaWxhdGVyYWwiLA0KIlJlbGF0aXZlLkVjY2VudHJpYy5Qb3dlci5CaWxhdGVyYWwiLCJNYXguUGVhay5Qb3dlci4uLkJNIiwgIk1heC5FY2NlbnRyaWMuUGVhay5Gb3JjZS4uTi4iLA0KIk1heC5SU0kuTW9kaWZpZWQuVkFMRCIsIk1heC5Db25jZW50cmljLlJQRC4uTi5zLiIsICJNYXguQ29uY2VudHJpYy5QZWFrLlZlbG9jaXR5Li5tLnMuIiwgIk1heC5FY2NlbnRyaWMuUGVhay5WZWxvY2l0eS4ubS5zLiIsICJNYXguUGVhay5MYW5kaW5nLkZvcmNlLi5OLiIsICJNQVguQ29uY2VudHJpYy5QZWFrLlBvd2VyLi5XLiIsIk1heC5DTUouSnVtcC5IZWlnaHQuLmNtLiIsDQoiTWF4LkNNSi5SU0kuTW9kaWZpZWQuLm0ucy4iLCJNYXguQ01KLkNvbmNlbnRyaWMuUlBELi5OLnMuIiwiTWF4LkNNSi5QZWFrLlBvd2VyLi5XLiIsIk1heC5DTUouUGVhay5MYW5kaW5nLkZvcmNlLi5OLiIsIkNNSi5Db25jZW50cmljLlJlbGF0aXZlLlBlYWsuUG93ZXIuLi5EaWZmZXJlbmNlLmZyb20uRmlyc3QiLCJDTUouRWNjZW50cmljLlJlbGF0aXZlLlBlYWsuUG93ZXIuLi5EaWZmZXJlbmNlLmZyb20uRmlyc3QiLCJFY2NlbnRyaWMuQXN5bW1ldHJ5IiwiQ29uY2VudHJpYy5Bc3ltbWV0cnkiDQopKSAgICAgICAgIzM0NDMgb2JzICYgMzYgdmFycyANCg0KI09USEVSIFBPU1NJQkxFIEZJTkFMIERBVEFTRVQNCmNtal9zIDwtIENNSl9TICU+JQ0KbmEub21pdCgpICAjNTYyIG9icyAmIDM2IHZhcnMNCmNtal9zW2Ntal9zPT0iIl0gPC0gTkENCg0KQ01KX1NbQ01KX1M9PSIiXSA8LSBOQQ0KDQojY29tYmluaW5nIHZhbHVlcyBmcm9tIGRpZmZlcmVudCBvYnNlcnZhdGlvbnMgaW50byBvbmUNCkNNSl9zIDwtIENNSl9TICU+JQ0KbXV0YXRlKERhdGUgPSBhcy5EYXRlKERhdGUsIGZvcm1hdCA9ICclbS8lZC8lWScpKSAlPiUNCiAgZ3JvdXBfYnkoYW5vbl9pZCwgRGF0ZSwgVGVzdC5UeXBlKSAlPiUNCiAgc3VtbWFyaXNlKFdlaWdodC4ua2cuID0gbWVhbihXZWlnaHQuLmtnLiwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIENvdW50ZXJtb3ZlbWVudC5EZXB0aC4uY20uPSBtZWFuKENvdW50ZXJtb3ZlbWVudC5EZXB0aC4uY20uLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIFBlYWsuUG93ZXIuLi5CTS4uVy5rZy49IG1lYW4oUGVhay5Qb3dlci4uLkJNLi5XLmtnLiwgbmEucm09VFJVRSksDQogICAgICAgICAgICBMYW5kaW5nLlJGRC4uTi5zLj0gbWVhbihMYW5kaW5nLlJGRC4uTi5zLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIEVjY2VudHJpYy5Db25jZW50cmljLk1lYW4uRm9yY2UuUmF0aW89IG1lYW4oRWNjZW50cmljLkNvbmNlbnRyaWMuTWVhbi5Gb3JjZS5SYXRpbyxuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIFBlYWsuTGFuZGluZy5Gb3JjZS4uQXN5bS4uLk4uPSBtZWFuKFBlYWsuTGFuZGluZy5Gb3JjZS4uQXN5bS4uLk4uLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgUGVhay5Qb3dlci4uVy49IG1lYW4oUGVhay5Qb3dlci4uVy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBDb25jZW50cmljLk1heGltdW0uUkZELi5OLnMuPSBtZWFuKENvbmNlbnRyaWMuTWF4aW11bS5SRkQuLk4ucy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBDb25jZW50cmljLk1heGltdW0uUkZELi5SaWdodC4uLk4ucy49IG1lYW4oQ29uY2VudHJpYy5NYXhpbXVtLlJGRC4uUmlnaHQuLi5OLnMuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgQ29uY2VudHJpYy5NYXhpbXVtLlJGRC4uTGVmdC4uLk4ucy49IG1lYW4oQ29uY2VudHJpYy5NYXhpbXVtLlJGRC4uTGVmdC4uLk4ucy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBFY2NlbnRyaWMuTWVhbi5CcmFraW5nLkZvcmNlLi5OLj0gbWVhbihFY2NlbnRyaWMuTWVhbi5CcmFraW5nLkZvcmNlLi5OLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5KdW1wLkhlaWdodC4uY20uPSBtZWFuKE1heC5KdW1wLkhlaWdodC4uY20uLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkNvbmNlbnRyaWMuUGVhay5Gb3JjZS4uTi49IG1lYW4oTWF4LkNvbmNlbnRyaWMuUGVhay5Gb3JjZS4uTi4sbmEucm09VFJVRSksDQogICAgICAgICAgICBSZWxhdGl2ZS5Db25jZW50cmljLlBvd2VyLkJpbGF0ZXJhbD0gbWVhbihSZWxhdGl2ZS5Db25jZW50cmljLlBvd2VyLkJpbGF0ZXJhbCxuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIFJlbGF0aXZlLkVjY2VudHJpYy5Qb3dlci5CaWxhdGVyYWw9IG1lYW4oUmVsYXRpdmUuRWNjZW50cmljLlBvd2VyLkJpbGF0ZXJhbCxuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5QZWFrLlBvd2VyLi4uQk09IG1lYW4oTWF4LlBlYWsuUG93ZXIuLi5CTSxuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5FY2NlbnRyaWMuUGVhay5Gb3JjZS4uTi49IG1lYW4oTWF4LkVjY2VudHJpYy5QZWFrLkZvcmNlLi5OLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5SU0kuTW9kaWZpZWQuVkFMRD0gbWVhbihNYXguUlNJLk1vZGlmaWVkLlZBTEQsbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguQ29uY2VudHJpYy5SUEQuLk4ucy49IG1lYW4oTWF4LkNvbmNlbnRyaWMuUlBELi5OLnMuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkNvbmNlbnRyaWMuUGVhay5WZWxvY2l0eS4ubS5zLj0gbWVhbihNYXguQ29uY2VudHJpYy5QZWFrLlZlbG9jaXR5Li5tLnMuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkVjY2VudHJpYy5QZWFrLlZlbG9jaXR5Li5tLnMuPSBtZWFuKE1heC5FY2NlbnRyaWMuUGVhay5WZWxvY2l0eS4ubS5zLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5QZWFrLkxhbmRpbmcuRm9yY2UuLk4uPSBtZWFuKE1heC5QZWFrLkxhbmRpbmcuRm9yY2UuLk4uLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTUFYLkNvbmNlbnRyaWMuUGVhay5Qb3dlci4uVy49IG1lYW4oTUFYLkNvbmNlbnRyaWMuUGVhay5Qb3dlci4uVy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguQ01KLkp1bXAuSGVpZ2h0Li5jbS49IG1lYW4oTWF4LkNNSi5KdW1wLkhlaWdodC4uY20uLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkNNSi5SU0kuTW9kaWZpZWQuLm0ucy49IG1lYW4oTWF4LkNNSi5SU0kuTW9kaWZpZWQuLm0ucy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguQ01KLkNvbmNlbnRyaWMuUlBELi5OLnMuPSBtZWFuKE1heC5DTUouQ29uY2VudHJpYy5SUEQuLk4ucy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguQ01KLlBlYWsuUG93ZXIuLlcuPSBtZWFuKE1heC5DTUouUGVhay5Qb3dlci4uVy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguQ01KLlBlYWsuTGFuZGluZy5Gb3JjZS4uTi49IG1lYW4oTWF4LkNNSi5QZWFrLkxhbmRpbmcuRm9yY2UuLk4uLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgQ01KLkNvbmNlbnRyaWMuUmVsYXRpdmUuUGVhay5Qb3dlci4uLkRpZmZlcmVuY2UuZnJvbS5GaXJzdD0gbWVhbihDTUouQ29uY2VudHJpYy5SZWxhdGl2ZS5QZWFrLlBvd2VyLi4uRGlmZmVyZW5jZS5mcm9tLkZpcnN0LG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgQ01KLkVjY2VudHJpYy5SZWxhdGl2ZS5QZWFrLlBvd2VyLi4uRGlmZmVyZW5jZS5mcm9tLkZpcnN0PSBtZWFuKENNSi5FY2NlbnRyaWMuUmVsYXRpdmUuUGVhay5Qb3dlci4uLkRpZmZlcmVuY2UuZnJvbS5GaXJzdCxuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIFBvc2l0aW9uPSBnZXRfbW9kZShQb3NpdGlvbiksDQogICAgICAgICAgICBFY2NlbnRyaWMuQXN5bW1ldHJ5PSBnZXRfbW9kZShFY2NlbnRyaWMuQXN5bW1ldHJ5KSwNCiAgICAgICAgICAgIENvbmNlbnRyaWMuQXN5bW1ldHJ5PSBnZXRfbW9kZShDb25jZW50cmljLkFzeW1tZXRyeSksDQogICAgICAgICAgICAuZ3JvdXBzID0gJ2Ryb3AnDQogICAgICAgICAgICAgICkgICAgICAgICAgICAgICAjIDEwNzcgb2JzICYgMzIgdmFycyAtPiAxNTcxDQoNCkNNSl9zb2MgPC0gQ01KX3MgJT4lDQogIG5hLm9taXQoKSAgICM2MjEgb2JzICYgMzIgdmFycyAtPiA2MDAgLT4gMjU3IG9icyAmIDM2IHZhcnMgDQpgYGANCg0KYGBge3J9DQojc2VsZWN0cyBjb3VudGVyIG1vdmVtZW50IGp1bXBzIGFub3RoZXIgd2F5IHdpdGggbm9ybWF0aXZlIGluZm9ybWF0aW9uDQpzIDwtIEZvcmNlZGVja3NfUyAlPiUNCiAgZmlsdGVyKFRlc3QuVHlwZSA9PSAnQ01KJykgJT4lDQogIGRwbHlyOjpzZWxlY3QoImFub25faWQiLCJEYXRlIiwiUG9zaXRpb24iLCJUZXN0LlR5cGUiLCJDb3VudGVybW92ZW1lbnQuRGVwdGguLmNtLiIsIlBlYWsuUG93ZXIuLi5CTS4uVy5rZy4iLCJMYW5kaW5nLlJGRC4uTi5zLiIsICJFY2NlbnRyaWMuQ29uY2VudHJpYy5NZWFuLkZvcmNlLlJhdGlvIiwgIlBlYWsuTGFuZGluZy5Gb3JjZS4uQXN5bS4uLk4uIiwgIlBlYWsuUG93ZXIuLlcuIiwgIkNvbmNlbnRyaWMuUkZELi5OLnMuIiwgIkNvbmNlbnRyaWMuUkZELi5MZWZ0Li4uTi5zLiIsIkNvbmNlbnRyaWMuUkZELi5SaWdodC4uLk4ucy4iLCAiQ29uY2VudHJpYy5UaW1lLnRvLlBlYWsuRm9yY2UuLnMuIiwgIkVjY2VudHJpYy5NZWFuLkJyYWtpbmcuRm9yY2UuLk4uIiwgIkxhbmRpbmcuTmV0LlBlYWsuRm9yY2UuLi5CTS4uTi5rZy4iLCAiUGVhay5OZXQuVGFrZW9mZi5Gb3JjZS4uLkJNLi5OLmtnLiIsICJDb25jZW50cmljLlJQRC4uLkJNLi5XLnMua2cuIiwgIkZvcmNlLmF0LlBlYWsuUG93ZXIuLk4uIiwgIkVjY2VudHJpYy5NZWFuLkRlY2VsZXJhdGlvbi5Gb3JjZS4uTi4iLCAiRWNjZW50cmljLlBlYWsuRm9yY2UuLk4uIiwgIlJTSS5Nb2RpZmllZC4ubS5zLiIsICJDTUouU3RpZmZuZXNzLi5MZWZ0Li4uTi5tLiIsICJDTUouU3RpZmZuZXNzLi5SaWdodC4uLk4ubS4iLCAiRWNjZW50cmljLkFzeW1tZXRyeSIsIkNvbmNlbnRyaWMuQXN5bW1ldHJ5IiwgIlBlYWsuTGFuZGluZy5Bc3ltbWV0cnkiLCAiRFNJIiwgIkRTSS5CdWNrZXQiLCAiRWNjZW50cmljLlBlYWsuUG93ZXIuLi5CTS4uVy5rZy4iLCAiSnVtcC5IZWlnaHQuLkltcC5Nb20uLi5jbS4iLCAiRWNjZW50cmljLkR1cmF0aW9uLi5zLiIsICJFY2NlbnRyaWMuRGVjZWxlcmF0aW9uLkltcHVsc2UuLk5zLiIpICU+JQ0KICBuYS5vbWl0KCkNCg0KI2NhbGN1bGF0ZXMgZGlmZmVyZW5jZXMgZnJvbSBub3JtIGFuZCBtYWtlcyBEYXRlIGEgZGF0ZSBvYmplY3QNCnMgPC0gcyAlPiUNCiAgbXV0YXRlKERhdGUgPSBhcy5EYXRlKERhdGUsIGZvcm1hdCA9ICclbS8lZC8lWScpLA0KICAgICAgICAgUlNJLk1vZGlmaWVkLi5tLnMuID0gUlNJLk1vZGlmaWVkLi5tLnMuIC8gMTAwLA0KICAgICAgICAgUlNJLk1vZGlmaWVkLkRpZmYuTm9ybSA9IChSU0kuTW9kaWZpZWQuLm0ucy4gLSAwLjQxNikgLyAwLjQxNiwNCiAgICAgICAgIEVjYy5QZWFrLlBvd2VyLlJlbC5EaWZmLk5vcm0gPSAoRWNjZW50cmljLlBlYWsuUG93ZXIuLi5CTS4uVy5rZy4gLSAxOCkgLyAxOCwNCiAgICAgICAgIEp1bXAuSGVpZ2guRGlmZi5Ob3JtID0gKEp1bXAuSGVpZ2h0Li5JbXAuTW9tLi4uY20uIC0gMzApIC8gMzAsDQogICAgICAgICBFY2MuRHVyYXRpb24uRGlmZi5Ob3JtID0gKEVjY2VudHJpYy5EdXJhdGlvbi4ucy4gLSAwLjQ5KSAvIDAuNDksDQogICAgICAgICBFY2MuRGVjZWxlcmF0aW9uLkltcHVsc2UuRGlmZi5Ob3JtID0gKEVjY2VudHJpYy5EZWNlbGVyYXRpb24uSW1wdWxzZS4uTnMuIC0gODEuNSkgLyA4MS41LA0KICAgICAgICAgU3BvcnQgPSAnU29jY2VyJw0KICApDQpgYGANCg0KYGBge3J9DQojMiBURVNUIFRZUEU9IEhKDQpISl9TIDwtIEZvcmNlZGVja3NfUyAlPiUNCiAgZmlsdGVyKFRlc3QuVHlwZT09IkhKIikgICU+JSAgIzU3NSBvYnMNCiAgZHBseXI6OnNlbGVjdCgiYW5vbl9pZCIsICJEYXRlIiwgIkNvcnJlY3RlZC5TdGFuZGluZy5XZWlnaHQuLktnLiIsICJNZWFuLlJTSS4uRmxpZ2h0LkNvbnRhY3QuVGltZS4iLCAiQWN0aXZlLlN0aWZmbmVzcy4uTi5tLiIsICJCZXN0LkF2ZXJhZ2UuRm9yY2UuLk4uIiwgIkJlc3QuQXZlcmFnZS5Gb3JjZS4uQXN5bS4uLk4uIiwgIkJlc3QuVGltZS50by5QZWFrLkZvcmNlLi5tcy4iLCAiQmVzdC5Db250YWN0LlRpbWUuLm1zLiIsICJCZXN0LkZsaWdodC5UaW1lLi5tcy4iLCAiQmVzdC5JbXB1bHNlLi5OLnMuIiwgIkJlc3QuUGVhay5Gb3JjZS4uTi4iLCAiQmVzdC5QZWFrLkZvcmNlLi5Bc3ltLi4uTi4iLCAiTWVhbi5BdmVyYWdlLkZvcmNlLi5OLiIsICJNZWFuLkF2ZXJhZ2UuRm9yY2UuLkFzeW0uLi5OLiIsICJNZWFuLkxhbmRpbmcuUkZELi5OLnMuIiwgIk1lYW4uTGFuZGluZy5SRkQuLkFzeW0uLi5OLnMuIiwgIlN0aWZmbmVzcy5GYXRpZ3VlLi4uLiIsICJTdGlmZm5lc3MuRmF0aWd1ZS4uQXN5bS4uLi4uIiwgIk1heC5KdW1wLkhlaWdodC4uY20uIiwgIkhKLlJTSSIsICJNZWFuLkZsaWdodC5UaW1lLi5tcy4iLCAiTWVhbi5Db250YWN0LlRpbWUuLm1zLiIpICU+JQ0KICBtdXRhdGUoRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0ID0gJyVtLyVkLyVZJykpICU+JQ0KICBuYS5vbWl0KCkgJT4lDQogIG11dGF0ZShTcG9ydCA9ICdTb2NjZXInKQ0KICAgICAgICAgICAgICAgICAjNTU2IG9icyAmIDIwIHZhcnMNCmBgYA0KDQpgYGB7cn0NCiMzIFRFU1QgVFlQRS0gU0xKDQpTTEpfUyA8LSBGb3JjZWRlY2tzX1MgJT4lDQogIGZpbHRlcihUZXN0LlR5cGU9PSJTTEoiKSAgIyA0NTUgb2JzDQoNCiNpbXBvcnRhbnQgdmFyaWFibGVzIA0KU0xKX1MgPC0gc3Vic2V0KFNMSl9TLCBzZWxlY3QgPSBjKCJhbm9uX2lkIiwgIkRhdGUiLCAiUG9zaXRpb24iLCAiV2VpZ2h0Li5rZy4iLCAiSnVtcC5IZWlnaHQuLkZsaWdodC5UaW1lLi4uY20uIiwgICJKdW1wLkhlaWdodC4uSW1wLk1vbS4uLmNtLiIsICJNYXguSnVtcC5IZWlnaHQuLmNtLiIsICJNYXguU2luZ2xlLkxlZy5KdW1wLkhlaWdodC5MZWZ0IiwgIk1heC5TaW5nbGUuTGVnLkp1bXAuSGVpZ2h0LlJpZ2h0IiwgIkZpcnN0LlNMSi5KdW1wLkhlaWdodCIsICJNYXguQ29uY2VudHJpYy5QZWFrLlZlbG9jaXR5Li5tLnMuIiwgIk1heC5FY2NlbnRyaWMuUGVhay5WZWxvY2l0eS4ubS5zLiIsICJSU0kuTW9kaWZpZWQuLm0ucy4iLCAiTWF4LlJTSS5Nb2RpZmllZC4ubS5zLiIsICJNYXguUlNJLk1vZGlmaWVkLlZBTEQiLCAiRWNjZW50cmljLk1lYW4uQnJha2luZy5Gb3JjZS4uTi4iLCAiTGFuZGluZy5SRkQuLk4ucy4iLCJDb25jZW50cmljLk1heGltdW0uUkZELi5OLnMuIiwgIkNvbmNlbnRyaWMuTWF4aW11bS5SRkQuLlJpZ2h0Li4uTi5zLiIsIkNvbmNlbnRyaWMuTWF4aW11bS5SRkQuLkxlZnQuLi5OLnMuIiwgIkNvbmNlbnRyaWMuSW1wdWxzZS4uTnMuIiwgIkNvbmNlbnRyaWMuSW1wdWxzZS4uTGVmdC4uLk5zLiIsICJDb25jZW50cmljLkltcHVsc2UuLlJpZ2h0Li4uTnMuIiwgIk1heC5Db25jZW50cmljLlBlYWsuRm9yY2UuLk4uIiwgIk1heC5FY2NlbnRyaWMuUGVhay5Gb3JjZS4uTi4iDQopKSAgICAgICAgICAgICAgICAgICAgICAgICM0NTUgb2JzICYgMjUgdmFycw0KDQpTTEpfU1tTTEpfUz09IiJdIDwtIE5BDQoNCiNjb21iaW5pbmcgdmFsdWVzIGZyb20gZGlmZmVyZW50IG9ic2VydmF0aW9ucyBpbnRvIG9uZQ0KU0xKX3MgPC0gU0xKX1MgJT4lDQptdXRhdGUoRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0ID0gJyVtLyVkLyVZJykpICU+JQ0KICBncm91cF9ieShhbm9uX2lkLCBEYXRlKSAlPiUNCiAgc3VtbWFyaXNlKFdlaWdodC4ua2cuID0gbWVhbihXZWlnaHQuLmtnLiwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIEp1bXAuSGVpZ2h0Li5GbGlnaHQuVGltZS4uLmNtLj0gbWVhbihKdW1wLkhlaWdodC4uRmxpZ2h0LlRpbWUuLi5jbS4sIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgSnVtcC5IZWlnaHQuLkltcC5Nb20uLi5jbS49IG1lYW4oSnVtcC5IZWlnaHQuLkltcC5Nb20uLi5jbS4sbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguSnVtcC5IZWlnaHQuLmNtLj0gbWVhbihNYXguSnVtcC5IZWlnaHQuLmNtLiAsbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguU2luZ2xlLkxlZy5KdW1wLkhlaWdodC5MZWZ0PSBtZWFuKE1heC5TaW5nbGUuTGVnLkp1bXAuSGVpZ2h0LkxlZnQgLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LlNpbmdsZS5MZWcuSnVtcC5IZWlnaHQuUmlnaHQ9IG1lYW4oTWF4LlNpbmdsZS5MZWcuSnVtcC5IZWlnaHQuUmlnaHQgLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgRmlyc3QuU0xKLkp1bXAuSGVpZ2h0PSBtZWFuKEZpcnN0LlNMSi5KdW1wLkhlaWdodCwgbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguQ29uY2VudHJpYy5QZWFrLlZlbG9jaXR5Li5tLnMuPSBtZWFuKE1heC5Db25jZW50cmljLlBlYWsuVmVsb2NpdHkuLm0ucy4sIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkVjY2VudHJpYy5QZWFrLlZlbG9jaXR5Li5tLnMuPSBtZWFuKE1heC5FY2NlbnRyaWMuUGVhay5WZWxvY2l0eS4ubS5zLiwgbmEucm09VFJVRSksDQogICAgICAgICAgICBSU0kuTW9kaWZpZWQuLm0ucy49IG1lYW4oUlNJLk1vZGlmaWVkLi5tLnMuLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5SU0kuTW9kaWZpZWQuLm0ucy49IG1lYW4oTWF4LlJTSS5Nb2RpZmllZC4ubS5zLiwgbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguUlNJLk1vZGlmaWVkLlZBTEQ9IG1lYW4oTWF4LlJTSS5Nb2RpZmllZC5WQUxELCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIEVjY2VudHJpYy5NZWFuLkJyYWtpbmcuRm9yY2UuLk4uPSBtZWFuKEVjY2VudHJpYy5NZWFuLkJyYWtpbmcuRm9yY2UuLk4uLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIExhbmRpbmcuUkZELi5OLnMuPSBtZWFuKExhbmRpbmcuUkZELi5OLnMuLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIENvbmNlbnRyaWMuTWF4aW11bS5SRkQuLk4ucy49IG1lYW4oQ29uY2VudHJpYy5NYXhpbXVtLlJGRC4uTi5zLiwgbmEucm09VFJVRSksDQogICAgICAgICAgICBDb25jZW50cmljLk1heGltdW0uUkZELi5SaWdodC4uLk4ucy49IG1lYW4oQ29uY2VudHJpYy5NYXhpbXVtLlJGRC4uUmlnaHQuLi5OLnMuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgQ29uY2VudHJpYy5NYXhpbXVtLlJGRC4uTGVmdC4uLk4ucy49IG1lYW4oQ29uY2VudHJpYy5NYXhpbXVtLlJGRC4uTGVmdC4uLk4ucy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBDb25jZW50cmljLkltcHVsc2UuLk5zLj0gbWVhbihDb25jZW50cmljLkltcHVsc2UuLk5zLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIENvbmNlbnRyaWMuSW1wdWxzZS4uTGVmdC4uLk5zLj0gbWVhbihDb25jZW50cmljLkltcHVsc2UuLkxlZnQuLi5Ocy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBDb25jZW50cmljLkltcHVsc2UuLlJpZ2h0Li4uTnMuPSBtZWFuKENvbmNlbnRyaWMuSW1wdWxzZS4uUmlnaHQuLi5Ocy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguQ29uY2VudHJpYy5QZWFrLkZvcmNlLi5OLj0gbWVhbihNYXguQ29uY2VudHJpYy5QZWFrLkZvcmNlLi5OLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5FY2NlbnRyaWMuUGVhay5Gb3JjZS4uTi49IG1lYW4oTWF4LkVjY2VudHJpYy5QZWFrLkZvcmNlLi5OLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIFBvc2l0aW9uPSBnZXRfbW9kZShQb3NpdGlvbiksDQogICAgICAgICAgICAuZ3JvdXBzID0gJ2Ryb3AnDQogICAgICAgICAgICAgICkgICAjODMgb2JzIDI1IHZhcnMNCmBgYA0KDQpgYGB7cn0NCiM0IFRFU1QgVFlQRS0gSU1UUA0KSU1UUF9TIDwtIEZvcmNlZGVja3NfUyAlPiUNCiAgZmlsdGVyKFRlc3QuVHlwZT09IklNVFAiKSAlPiUgICAjMjAwIG9icyANCiAgc2VsZWN0KCJhbm9uX2lkIiwgIkRhdGUiLCAiQmFzZWxpbmUuRm9yY2UuLk4uIiwiQmFzZWxpbmUuRm9yY2UuLkFzeW0uLi5OLiIsICJQZWFrLlZlcnRpY2FsLkZvcmNlLi5OLiIsICJQZWFrLlZlcnRpY2FsLkZvcmNlLi4uQk0uLk4ua2cuIiwgIlBlYWsuVmVydGljYWwuRm9yY2UuLkFzeW0uLi5OLiIsICJSRkQuLi41MG1zLi5OLnMuIiwgIlJGRC4uLjUwbXMuLkFzeW0uLi5OLnMuIiwgIlJGRC4uLjEwMG1zLi5OLnMuIiwgIlJGRC4uLjEwMG1zLi5Bc3ltLi4uTi5zLiIsICJSRkQuLi4xNTBtcy4uTi5zLiIsICJSRkQuLi4xNTBtcy4uQXN5bS4uLk4ucy4iLCAiUkZELi4uMjAwbXMuLk4ucy4iLCAiUkZELi4uMjAwbXMuLkFzeW0uLi5OLnMuIiwgIk5ldC5QZWFrLlZlcnRpY2FsLkZvcmNlLi5OLnMuIiwgIk5ldC5QZWFrLlZlcnRpY2FsLkZvcmNlLi5Bc3ltLi4uTi5zLiIsICJGb3JjZS5hdC4yMDBtcy4uLkJNLi5OLmtnLiIsICJFY2NlbnRyaWMuQXN5bW1ldHJ5IiwgIkNvbmNlbnRyaWMuQXN5bW1ldHJ5IiwiTUVBTi5FY2NlbnRyaWMuTWVhbi5Gb3JjZS5MZWZ0IiwgIk1FQU4uRWNjZW50cmljLk1lYW4uRm9yY2UuUmlnaHQiLCAiTUVBTi5Db25jZW50cmljLk1lYW4uRm9yY2UuTGVmdCIsICJNRUFOLkNvbmNlbnRyaWMuTWVhbi5Gb3JjZS5SaWdodCIsICJNRUFOLkNvbmNlbnRyaWMuTWVhbi5Gb3JjZS5Bc3ltIiwgIk1FQU4uUGVhay5MYW5kaW5nLkZvcmNlLkFzeW0iLCAgIk1FQU4uUmVsYXRpdmUuUGVhay5Qb3dlciIsICJNRUFOLkNNSi5Db25jZW50cmljLkZvcmNlIiwgIk1FQU4uUGVhay5MYW5kaW5nLkZvcmNlLkxlZnQiLCAiTUVBTi5QZWFrLkxhbmRpbmcuRm9yY2UuUmlnaHQiLCAiRFNJIiwgIkRTSS5CdWNrZXQiKSAlPiUNCiAgbXV0YXRlKERhdGUgPSBhcy5EYXRlKERhdGUsIGZvcm1hdCA9ICclbS8lZC8lWScpKSAlPiUNCiAgbmEub21pdCgpICU+JQ0KICBtdXRhdGUoU3BvcnQgPSAnU29jY2VyJykgICAjNjggb2JzICYgMzAgdmFycw0KYGBgDQoNCiNGb3JjZWRlY2tzIChWQUxEKSBMYWNyb3NzZSBEYXRhDQpgYGB7cn0NCiMxIDogVEVTVCBUWVBFPSBDTUoNCiNzZWxlY3RzIHZhcmlhYmxlcyBvZiBpbnRlcmVzdA0KQ01KX0wgPC0gc3Vic2V0KEZvcmNlZGVja3NfTCwgc2VsZWN0ID0gYygiYW5vbl9pZCIsIkRhdGUiLCJQb3NpdGlvbiIsIlRlc3QuVHlwZSIsIldlaWdodC4ua2cuIiwiQ291bnRlcm1vdmVtZW50LkRlcHRoLi5jbS4iLCJQZWFrLlBvd2VyLi4uQk0uLlcua2cuIiwiTGFuZGluZy5SRkQuLk4ucy4iLCAiRWNjZW50cmljLkNvbmNlbnRyaWMuTWVhbi5Gb3JjZS5SYXRpbyIsICJQZWFrLkxhbmRpbmcuRm9yY2UuLkFzeW0uLi5OLiIsICJQZWFrLlBvd2VyLi5XLiIsIkNvbmNlbnRyaWMuTWF4aW11bS5SRkQuLk4ucy4iLCJDb25jZW50cmljLk1heGltdW0uUkZELi5SaWdodC4uLk4ucy4iLCJDb25jZW50cmljLk1heGltdW0uUkZELi5MZWZ0Li4uTi5zLiIsIkVjY2VudHJpYy5NZWFuLkJyYWtpbmcuRm9yY2UuLk4uIiwgIk1heC5KdW1wLkhlaWdodC4uY20uIiwgIk1heC5Db25jZW50cmljLlBlYWsuRm9yY2UuLk4uIiwgIlJlbGF0aXZlLkNvbmNlbnRyaWMuUG93ZXIuQmlsYXRlcmFsIiwNCiJSZWxhdGl2ZS5FY2NlbnRyaWMuUG93ZXIuQmlsYXRlcmFsIiwiTWF4LlBlYWsuUG93ZXIuLi5CTSIsICJNYXguRWNjZW50cmljLlBlYWsuRm9yY2UuLk4uIiwNCiJNYXguUlNJLk1vZGlmaWVkLlZBTEQiLCJNYXguQ29uY2VudHJpYy5SUEQuLk4ucy4iLCAiTWF4LkNvbmNlbnRyaWMuUGVhay5WZWxvY2l0eS4ubS5zLiIsICJNYXguRWNjZW50cmljLlBlYWsuVmVsb2NpdHkuLm0ucy4iLCAiTWF4LlBlYWsuTGFuZGluZy5Gb3JjZS4uTi4iLCAiTUFYLkNvbmNlbnRyaWMuUGVhay5Qb3dlci4uVy4iLCJNYXguQ01KLkp1bXAuSGVpZ2h0Li5jbS4iLA0KIk1heC5DTUouUlNJLk1vZGlmaWVkLi5tLnMuIiwiTWF4LkNNSi5Db25jZW50cmljLlJQRC4uTi5zLiIsIk1heC5DTUouUGVhay5Qb3dlci4uVy4iLCJNYXguQ01KLlBlYWsuTGFuZGluZy5Gb3JjZS4uTi4iLCJDTUouQ29uY2VudHJpYy5SZWxhdGl2ZS5QZWFrLlBvd2VyLi4uRGlmZmVyZW5jZS5mcm9tLkZpcnN0IiwiQ01KLkVjY2VudHJpYy5SZWxhdGl2ZS5QZWFrLlBvd2VyLi4uRGlmZmVyZW5jZS5mcm9tLkZpcnN0IiwiRWNjZW50cmljLkFzeW1tZXRyeSIsIkNvbmNlbnRyaWMuQXN5bW1ldHJ5Ig0KKSkgICAgICAgICMxOTM5IG9icyAmIDM2IHZhcnMgDQoNCiNwb3NzaWJsZSBvdGhlciBmaW5hbCBkYXRhc2V0DQpjbWpfbCA8LSBDTUpfTCAlPiUNCiAgbmEub21pdCgpICAgICAgIzM3NyBvYnMgDQoNCkNNSl9MW0NNSl9MPT0iIl0gPC0gTkENCg0KI2NvbWJpbmluZyB2YWx1ZXMgZnJvbSBkaWZmZXJlbnQgb2JzZXJ2YXRpb25zIGludG8gb25lDQpDTUpfbCA8LSBDTUpfTCAlPiUNCm11dGF0ZShEYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAnJW0vJWQvJVknKSkgJT4lDQogIGdyb3VwX2J5KGFub25faWQsIERhdGUsIFRlc3QuVHlwZSkgJT4lDQogIHN1bW1hcmlzZShXZWlnaHQuLmtnLiA9IG1lYW4oV2VpZ2h0Li5rZy4sIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBDb3VudGVybW92ZW1lbnQuRGVwdGguLmNtLj0gbWVhbihDb3VudGVybW92ZW1lbnQuRGVwdGguLmNtLiwgbmEucm09VFJVRSksDQogICAgICAgICAgICBQZWFrLlBvd2VyLi4uQk0uLlcua2cuPSBtZWFuKFBlYWsuUG93ZXIuLi5CTS4uVy5rZy4sIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTGFuZGluZy5SRkQuLk4ucy49IG1lYW4oTGFuZGluZy5SRkQuLk4ucy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBFY2NlbnRyaWMuQ29uY2VudHJpYy5NZWFuLkZvcmNlLlJhdGlvPSBtZWFuKEVjY2VudHJpYy5Db25jZW50cmljLk1lYW4uRm9yY2UuUmF0aW8sbmEucm09VFJVRSksDQogICAgICAgICAgICBQZWFrLkxhbmRpbmcuRm9yY2UuLkFzeW0uLi5OLj0gbWVhbihQZWFrLkxhbmRpbmcuRm9yY2UuLkFzeW0uLi5OLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIFBlYWsuUG93ZXIuLlcuPSBtZWFuKFBlYWsuUG93ZXIuLlcuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgQ29uY2VudHJpYy5NYXhpbXVtLlJGRC4uTi5zLj0gbWVhbihDb25jZW50cmljLk1heGltdW0uUkZELi5OLnMuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgQ29uY2VudHJpYy5NYXhpbXVtLlJGRC4uUmlnaHQuLi5OLnMuPSBtZWFuKENvbmNlbnRyaWMuTWF4aW11bS5SRkQuLlJpZ2h0Li4uTi5zLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIENvbmNlbnRyaWMuTWF4aW11bS5SRkQuLkxlZnQuLi5OLnMuPSBtZWFuKENvbmNlbnRyaWMuTWF4aW11bS5SRkQuLkxlZnQuLi5OLnMuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgRWNjZW50cmljLk1lYW4uQnJha2luZy5Gb3JjZS4uTi49IG1lYW4oRWNjZW50cmljLk1lYW4uQnJha2luZy5Gb3JjZS4uTi4sbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguSnVtcC5IZWlnaHQuLmNtLj0gbWVhbihNYXguSnVtcC5IZWlnaHQuLmNtLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5Db25jZW50cmljLlBlYWsuRm9yY2UuLk4uPSBtZWFuKE1heC5Db25jZW50cmljLlBlYWsuRm9yY2UuLk4uLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgUmVsYXRpdmUuQ29uY2VudHJpYy5Qb3dlci5CaWxhdGVyYWw9IG1lYW4oUmVsYXRpdmUuQ29uY2VudHJpYy5Qb3dlci5CaWxhdGVyYWwsbmEucm09VFJVRSksDQogICAgICAgICAgICBSZWxhdGl2ZS5FY2NlbnRyaWMuUG93ZXIuQmlsYXRlcmFsPSBtZWFuKFJlbGF0aXZlLkVjY2VudHJpYy5Qb3dlci5CaWxhdGVyYWwsbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguUGVhay5Qb3dlci4uLkJNPSBtZWFuKE1heC5QZWFrLlBvd2VyLi4uQk0sbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguRWNjZW50cmljLlBlYWsuRm9yY2UuLk4uPSBtZWFuKE1heC5FY2NlbnRyaWMuUGVhay5Gb3JjZS4uTi4sbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguUlNJLk1vZGlmaWVkLlZBTEQ9IG1lYW4oTWF4LlJTSS5Nb2RpZmllZC5WQUxELG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkNvbmNlbnRyaWMuUlBELi5OLnMuPSBtZWFuKE1heC5Db25jZW50cmljLlJQRC4uTi5zLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5Db25jZW50cmljLlBlYWsuVmVsb2NpdHkuLm0ucy49IG1lYW4oTWF4LkNvbmNlbnRyaWMuUGVhay5WZWxvY2l0eS4ubS5zLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5FY2NlbnRyaWMuUGVhay5WZWxvY2l0eS4ubS5zLj0gbWVhbihNYXguRWNjZW50cmljLlBlYWsuVmVsb2NpdHkuLm0ucy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguUGVhay5MYW5kaW5nLkZvcmNlLi5OLj0gbWVhbihNYXguUGVhay5MYW5kaW5nLkZvcmNlLi5OLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1BWC5Db25jZW50cmljLlBlYWsuUG93ZXIuLlcuPSBtZWFuKE1BWC5Db25jZW50cmljLlBlYWsuUG93ZXIuLlcuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkNNSi5KdW1wLkhlaWdodC4uY20uPSBtZWFuKE1heC5DTUouSnVtcC5IZWlnaHQuLmNtLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5DTUouUlNJLk1vZGlmaWVkLi5tLnMuPSBtZWFuKE1heC5DTUouUlNJLk1vZGlmaWVkLi5tLnMuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkNNSi5Db25jZW50cmljLlJQRC4uTi5zLj0gbWVhbihNYXguQ01KLkNvbmNlbnRyaWMuUlBELi5OLnMuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkNNSi5QZWFrLlBvd2VyLi5XLj0gbWVhbihNYXguQ01KLlBlYWsuUG93ZXIuLlcuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkNNSi5QZWFrLkxhbmRpbmcuRm9yY2UuLk4uPSBtZWFuKE1heC5DTUouUGVhay5MYW5kaW5nLkZvcmNlLi5OLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIENNSi5Db25jZW50cmljLlJlbGF0aXZlLlBlYWsuUG93ZXIuLi5EaWZmZXJlbmNlLmZyb20uRmlyc3Q9IG1lYW4oQ01KLkNvbmNlbnRyaWMuUmVsYXRpdmUuUGVhay5Qb3dlci4uLkRpZmZlcmVuY2UuZnJvbS5GaXJzdCxuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIENNSi5FY2NlbnRyaWMuUmVsYXRpdmUuUGVhay5Qb3dlci4uLkRpZmZlcmVuY2UuZnJvbS5GaXJzdD0gbWVhbihDTUouRWNjZW50cmljLlJlbGF0aXZlLlBlYWsuUG93ZXIuLi5EaWZmZXJlbmNlLmZyb20uRmlyc3QsbmEucm09VFJVRSksDQogICAgICAgICAgICBQb3NpdGlvbj0gZ2V0X21vZGUoUG9zaXRpb24pLA0KICAgICAgICAgICAgRWNjZW50cmljLkFzeW1tZXRyeT0gZ2V0X21vZGUoRWNjZW50cmljLkFzeW1tZXRyeSksDQogICAgICAgICAgICBDb25jZW50cmljLkFzeW1tZXRyeT0gZ2V0X21vZGUoQ29uY2VudHJpYy5Bc3ltbWV0cnkpLA0KICAgICAgICAgICAgLmdyb3VwcyA9ICdkcm9wJw0KICAgICAgICAgICAgICApICAgICAgICAgICAgICAgIyAxMjM4IG9icyAmIDM2IHZhcnMNCg0KQ01KX2xheCA8LSBDTUpfbCAlPiUNCiAgbmEub21pdCgpICAgIzI3NyBvYnMgJiAzNiB2YXJzDQpgYGANCg0KYGBge3J9DQojc2VsZWN0cyBjb3VudGVyIG1vdmVtZW50IGp1bXBzIGFub3RoZXIgd2F5IHdpdGggbm9ybWF0aXZlIGluZm9ybWF0aW9uDQpsIDwtIEZvcmNlZGVja3NfTCAlPiUNCiAgZmlsdGVyKFRlc3QuVHlwZSA9PSAnQ01KJykgJT4lDQogIGRwbHlyOjpzZWxlY3QoImFub25faWQiLCJEYXRlIiwiUG9zaXRpb24iLCJUZXN0LlR5cGUiLCJDb3VudGVybW92ZW1lbnQuRGVwdGguLmNtLiIsIlBlYWsuUG93ZXIuLi5CTS4uVy5rZy4iLCJMYW5kaW5nLlJGRC4uTi5zLiIsICJFY2NlbnRyaWMuQ29uY2VudHJpYy5NZWFuLkZvcmNlLlJhdGlvIiwgIlBlYWsuTGFuZGluZy5Gb3JjZS4uQXN5bS4uLk4uIiwgIlBlYWsuUG93ZXIuLlcuIiwgIkNvbmNlbnRyaWMuUkZELi5OLnMuIiwgIkNvbmNlbnRyaWMuUkZELi5MZWZ0Li4uTi5zLiIsIkNvbmNlbnRyaWMuUkZELi5SaWdodC4uLk4ucy4iLCAiQ29uY2VudHJpYy5UaW1lLnRvLlBlYWsuRm9yY2UuLnMuIiwgIkVjY2VudHJpYy5NZWFuLkJyYWtpbmcuRm9yY2UuLk4uIiwgIkxhbmRpbmcuTmV0LlBlYWsuRm9yY2UuLi5CTS4uTi5rZy4iLCAiUGVhay5OZXQuVGFrZW9mZi5Gb3JjZS4uLkJNLi5OLmtnLiIsICJDb25jZW50cmljLlJQRC4uLkJNLi5XLnMua2cuIiwgIkZvcmNlLmF0LlBlYWsuUG93ZXIuLk4uIiwgIkVjY2VudHJpYy5NZWFuLkRlY2VsZXJhdGlvbi5Gb3JjZS4uTi4iLCAiRWNjZW50cmljLlBlYWsuRm9yY2UuLk4uIiwgIlJTSS5Nb2RpZmllZC4ubS5zLiIsICJDTUouU3RpZmZuZXNzLi5MZWZ0Li4uTi5tLiIsICJDTUouU3RpZmZuZXNzLi5SaWdodC4uLk4ubS4iLCAiRWNjZW50cmljLkFzeW1tZXRyeSIsIkNvbmNlbnRyaWMuQXN5bW1ldHJ5IiwgIlBlYWsuTGFuZGluZy5Bc3ltbWV0cnkiLCAiRFNJIiwgIkRTSS5CdWNrZXQiLCAiRWNjZW50cmljLlBlYWsuUG93ZXIuLi5CTS4uVy5rZy4iLCAiSnVtcC5IZWlnaHQuLkltcC5Nb20uLi5jbS4iLCAiRWNjZW50cmljLkR1cmF0aW9uLi5zLiIsICJFY2NlbnRyaWMuRGVjZWxlcmF0aW9uLkltcHVsc2UuLk5zLiIpICU+JQ0KICBuYS5vbWl0KCkNCg0KI2NhbGN1bGF0ZXMgZGlmZmVyZW5jZXMgZnJvbSBub3JtIGFuZCBtYWtlcyBEYXRlIGEgZGF0ZSBvYmplY3QNCmwgPC0gbCAlPiUNCiAgbXV0YXRlKERhdGUgPSBhcy5EYXRlKERhdGUsIGZvcm1hdCA9ICclbS8lZC8lWScpLA0KICAgICAgICAgUlNJLk1vZGlmaWVkLi5tLnMuID0gUlNJLk1vZGlmaWVkLi5tLnMuIC8gMTAwLA0KICAgICAgICAgUlNJLk1vZGlmaWVkLkRpZmYuTm9ybSA9IChSU0kuTW9kaWZpZWQuLm0ucy4gLSAwLjM1OSkgLyAwLjM1OSwNCiAgICAgICAgIEVjYy5QZWFrLlBvd2VyLlJlbC5EaWZmLk5vcm0gPSAoRWNjZW50cmljLlBlYWsuUG93ZXIuLi5CTS4uVy5rZy4gLSAxNikgLyAxNiwNCiAgICAgICAgIEp1bXAuSGVpZ2guRGlmZi5Ob3JtID0gKEp1bXAuSGVpZ2h0Li5JbXAuTW9tLi4uY20uIC0gMjkpIC8gMjksDQogICAgICAgICBFY2MuRHVyYXRpb24uRGlmZi5Ob3JtID0gKEVjY2VudHJpYy5EdXJhdGlvbi4ucy4gLSAwLjU1KSAvIDAuNTUsDQogICAgICAgICBFY2MuRGVjZWxlcmF0aW9uLkltcHVsc2UuRGlmZi5Ob3JtID0gKEVjY2VudHJpYy5EZWNlbGVyYXRpb24uSW1wdWxzZS4uTnMuIC0gODEuNSkgLyA4MS41LA0KICAgICAgICAgU3BvcnQgPSAnTGFjcm9zc2UnDQogICkNCmBgYA0KDQpgYGB7cn0NCiMyOiBURVNUIFRZUEU9IEhKDQpISl9MIDwtIEZvcmNlZGVja3NfTCAlPiUNCiAgZmlsdGVyKFRlc3QuVHlwZT09IkhKIikgICU+JSAgIzU4MiBvYnMNCiAgZHBseXI6OnNlbGVjdCgiYW5vbl9pZCIsICJEYXRlIiwgIkNvcnJlY3RlZC5TdGFuZGluZy5XZWlnaHQuLktnLiIsICJNZWFuLlJTSS4uRmxpZ2h0LkNvbnRhY3QuVGltZS4iLCAiQWN0aXZlLlN0aWZmbmVzcy4uTi5tLiIsICJCZXN0LkF2ZXJhZ2UuRm9yY2UuLk4uIiwgIkJlc3QuQXZlcmFnZS5Gb3JjZS4uQXN5bS4uLk4uIiwgIkJlc3QuVGltZS50by5QZWFrLkZvcmNlLi5tcy4iLCAiQmVzdC5Db250YWN0LlRpbWUuLm1zLiIsICJCZXN0LkZsaWdodC5UaW1lLi5tcy4iLCAiQmVzdC5JbXB1bHNlLi5OLnMuIiwgIkJlc3QuUGVhay5Gb3JjZS4uTi4iLCAiQmVzdC5QZWFrLkZvcmNlLi5Bc3ltLi4uTi4iLCAiTWVhbi5BdmVyYWdlLkZvcmNlLi5OLiIsICJNZWFuLkF2ZXJhZ2UuRm9yY2UuLkFzeW0uLi5OLiIsICJNZWFuLkxhbmRpbmcuUkZELi5OLnMuIiwgIk1lYW4uTGFuZGluZy5SRkQuLkFzeW0uLi5OLnMuIiwgIlN0aWZmbmVzcy5GYXRpZ3VlLi4uLiIsICJTdGlmZm5lc3MuRmF0aWd1ZS4uQXN5bS4uLi4uIiwgIk1heC5KdW1wLkhlaWdodC4uY20uIiwgIkhKLlJTSSIsICJNZWFuLkZsaWdodC5UaW1lLi5tcy4iLCAiTWVhbi5Db250YWN0LlRpbWUuLm1zLiIpICU+JQ0KICBtdXRhdGUoRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0ID0gJyVtLyVkLyVZJykpICU+JQ0KICBuYS5vbWl0KCkgJT4lDQogIG11dGF0ZShTcG9ydCA9ICdMYWNyb3NzZScpDQogICAgICAgICAgICAgICAgICM1NzMgb2JzICYgMjAgdmFycw0KYGBgDQoNCmBgYHtyfQ0KIzM6IFRFU1QgVFlQRTogU0xKDQpTTEpfTCA8LSBGb3JjZWRlY2tzX0wgJT4lDQogIGZpbHRlcihUZXN0LlR5cGU9PSJTTEoiKSAgIzE5MCBvYnMNCg0KI2ltcG9ydGFudCB2YXJpYWJsZXMgDQpTTEpfTCA8LSBzdWJzZXQoU0xKX0wsIHNlbGVjdCA9IGMoImFub25faWQiLCAiRGF0ZSIsICJQb3NpdGlvbiIsICJXZWlnaHQuLmtnLiIsICJKdW1wLkhlaWdodC4uRmxpZ2h0LlRpbWUuLi5jbS4iLCAgIkp1bXAuSGVpZ2h0Li5JbXAuTW9tLi4uY20uIiwgIk1heC5KdW1wLkhlaWdodC4uY20uIiwgIk1heC5TaW5nbGUuTGVnLkp1bXAuSGVpZ2h0LkxlZnQiLCAiTWF4LlNpbmdsZS5MZWcuSnVtcC5IZWlnaHQuUmlnaHQiLCAiRmlyc3QuU0xKLkp1bXAuSGVpZ2h0IiwgIk1heC5Db25jZW50cmljLlBlYWsuVmVsb2NpdHkuLm0ucy4iLCAiTWF4LkVjY2VudHJpYy5QZWFrLlZlbG9jaXR5Li5tLnMuIiwgIlJTSS5Nb2RpZmllZC4ubS5zLiIsICJNYXguUlNJLk1vZGlmaWVkLi5tLnMuIiwgIk1heC5SU0kuTW9kaWZpZWQuVkFMRCIsICJFY2NlbnRyaWMuTWVhbi5CcmFraW5nLkZvcmNlLi5OLiIsICJMYW5kaW5nLlJGRC4uTi5zLiIsIkNvbmNlbnRyaWMuTWF4aW11bS5SRkQuLk4ucy4iLCAiQ29uY2VudHJpYy5NYXhpbXVtLlJGRC4uUmlnaHQuLi5OLnMuIiwiQ29uY2VudHJpYy5NYXhpbXVtLlJGRC4uTGVmdC4uLk4ucy4iLCAiQ29uY2VudHJpYy5JbXB1bHNlLi5Ocy4iLCAiQ29uY2VudHJpYy5JbXB1bHNlLi5MZWZ0Li4uTnMuIiwgIkNvbmNlbnRyaWMuSW1wdWxzZS4uUmlnaHQuLi5Ocy4iLCAiTWF4LkNvbmNlbnRyaWMuUGVhay5Gb3JjZS4uTi4iLCAiTWF4LkVjY2VudHJpYy5QZWFrLkZvcmNlLi5OLiINCikpICAgICAgICAgICAgICAgICAgICAgICAgIzE5MCBvYnMgJiAyNSB2YXJzDQoNClNMSl9MW1NMSl9MPT0iIl0gPC0gTkENCg0KI2NvbWJpbmluZyB2YWx1ZXMgZnJvbSBkaWZmZXJlbnQgb2JzZXJ2YXRpb25zIGludG8gb25lDQpTTEpfbCA8LSBTTEpfTCAlPiUNCm11dGF0ZShEYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAnJW0vJWQvJVknKSkgJT4lDQogIGdyb3VwX2J5KGFub25faWQsIERhdGUpICU+JQ0KICBzdW1tYXJpc2UoV2VpZ2h0Li5rZy4gPSBtZWFuKFdlaWdodC4ua2cuLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgSnVtcC5IZWlnaHQuLkZsaWdodC5UaW1lLi4uY20uPSBtZWFuKEp1bXAuSGVpZ2h0Li5GbGlnaHQuVGltZS4uLmNtLiwgbmEucm09VFJVRSksDQogICAgICAgICAgICBKdW1wLkhlaWdodC4uSW1wLk1vbS4uLmNtLj0gbWVhbihKdW1wLkhlaWdodC4uSW1wLk1vbS4uLmNtLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5KdW1wLkhlaWdodC4uY20uPSBtZWFuKE1heC5KdW1wLkhlaWdodC4uY20uICxuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5TaW5nbGUuTGVnLkp1bXAuSGVpZ2h0LkxlZnQ9IG1lYW4oTWF4LlNpbmdsZS5MZWcuSnVtcC5IZWlnaHQuTGVmdCAsbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguU2luZ2xlLkxlZy5KdW1wLkhlaWdodC5SaWdodD0gbWVhbihNYXguU2luZ2xlLkxlZy5KdW1wLkhlaWdodC5SaWdodCAsbmEucm09VFJVRSksDQogICAgICAgICAgICBGaXJzdC5TTEouSnVtcC5IZWlnaHQ9IG1lYW4oRmlyc3QuU0xKLkp1bXAuSGVpZ2h0LCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5Db25jZW50cmljLlBlYWsuVmVsb2NpdHkuLm0ucy49IG1lYW4oTWF4LkNvbmNlbnRyaWMuUGVhay5WZWxvY2l0eS4ubS5zLiwgbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguRWNjZW50cmljLlBlYWsuVmVsb2NpdHkuLm0ucy49IG1lYW4oTWF4LkVjY2VudHJpYy5QZWFrLlZlbG9jaXR5Li5tLnMuLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIFJTSS5Nb2RpZmllZC4ubS5zLj0gbWVhbihSU0kuTW9kaWZpZWQuLm0ucy4sIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LlJTSS5Nb2RpZmllZC4ubS5zLj0gbWVhbihNYXguUlNJLk1vZGlmaWVkLi5tLnMuLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5SU0kuTW9kaWZpZWQuVkFMRD0gbWVhbihNYXguUlNJLk1vZGlmaWVkLlZBTEQsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgRWNjZW50cmljLk1lYW4uQnJha2luZy5Gb3JjZS4uTi49IG1lYW4oRWNjZW50cmljLk1lYW4uQnJha2luZy5Gb3JjZS4uTi4sIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTGFuZGluZy5SRkQuLk4ucy49IG1lYW4oTGFuZGluZy5SRkQuLk4ucy4sIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgQ29uY2VudHJpYy5NYXhpbXVtLlJGRC4uTi5zLj0gbWVhbihDb25jZW50cmljLk1heGltdW0uUkZELi5OLnMuLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIENvbmNlbnRyaWMuTWF4aW11bS5SRkQuLlJpZ2h0Li4uTi5zLj0gbWVhbihDb25jZW50cmljLk1heGltdW0uUkZELi5SaWdodC4uLk4ucy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBDb25jZW50cmljLk1heGltdW0uUkZELi5MZWZ0Li4uTi5zLj0gbWVhbihDb25jZW50cmljLk1heGltdW0uUkZELi5MZWZ0Li4uTi5zLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIENvbmNlbnRyaWMuSW1wdWxzZS4uTnMuPSBtZWFuKENvbmNlbnRyaWMuSW1wdWxzZS4uTnMuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgQ29uY2VudHJpYy5JbXB1bHNlLi5MZWZ0Li4uTnMuPSBtZWFuKENvbmNlbnRyaWMuSW1wdWxzZS4uTGVmdC4uLk5zLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIENvbmNlbnRyaWMuSW1wdWxzZS4uUmlnaHQuLi5Ocy49IG1lYW4oQ29uY2VudHJpYy5JbXB1bHNlLi5SaWdodC4uLk5zLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5Db25jZW50cmljLlBlYWsuRm9yY2UuLk4uPSBtZWFuKE1heC5Db25jZW50cmljLlBlYWsuRm9yY2UuLk4uLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkVjY2VudHJpYy5QZWFrLkZvcmNlLi5OLj0gbWVhbihNYXguRWNjZW50cmljLlBlYWsuRm9yY2UuLk4uLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgUG9zaXRpb249IGdldF9tb2RlKFBvc2l0aW9uKSwNCiAgICAgICAgICAgIC5ncm91cHMgPSAnZHJvcCcNCiAgICAgICAgICAgICAgKSAgICM2MCBvYnMgMjUgdmFycw0KYGBgDQoNCmBgYHtyfQ0KIzQgVEVTVCBUWVBFLSBJTVRQDQojRFNJDQojYmFsbGlzdGljLCBleHBsb3NpdmUsIGNvbmN1cnJlbnQgDQpJTVRQX0wgPC0gRm9yY2VkZWNrc19MICU+JQ0KICBmaWx0ZXIoVGVzdC5UeXBlPT0iSU1UUCIpICU+JSAgICMxMDAgb2JzIA0KICBzZWxlY3QoImFub25faWQiLCAiRGF0ZSIsICJCYXNlbGluZS5Gb3JjZS4uTi4iLCJCYXNlbGluZS5Gb3JjZS4uQXN5bS4uLk4uIiwgIlBlYWsuVmVydGljYWwuRm9yY2UuLk4uIiwgIlBlYWsuVmVydGljYWwuRm9yY2UuLi5CTS4uTi5rZy4iLCAiUGVhay5WZXJ0aWNhbC5Gb3JjZS4uQXN5bS4uLk4uIiwgIlJGRC4uLjUwbXMuLk4ucy4iLCAiUkZELi4uNTBtcy4uQXN5bS4uLk4ucy4iLCAiUkZELi4uMTAwbXMuLk4ucy4iLCAiUkZELi4uMTAwbXMuLkFzeW0uLi5OLnMuIiwgIlJGRC4uLjE1MG1zLi5OLnMuIiwgIlJGRC4uLjE1MG1zLi5Bc3ltLi4uTi5zLiIsICJSRkQuLi4yMDBtcy4uTi5zLiIsICJSRkQuLi4yMDBtcy4uQXN5bS4uLk4ucy4iLCAiTmV0LlBlYWsuVmVydGljYWwuRm9yY2UuLk4ucy4iLCAiTmV0LlBlYWsuVmVydGljYWwuRm9yY2UuLkFzeW0uLi5OLnMuIiwgIkZvcmNlLmF0LjIwMG1zLi4uQk0uLk4ua2cuIiwgIkVjY2VudHJpYy5Bc3ltbWV0cnkiLCAiQ29uY2VudHJpYy5Bc3ltbWV0cnkiLCJNRUFOLkVjY2VudHJpYy5NZWFuLkZvcmNlLkxlZnQiLCAiTUVBTi5FY2NlbnRyaWMuTWVhbi5Gb3JjZS5SaWdodCIsICJNRUFOLkNvbmNlbnRyaWMuTWVhbi5Gb3JjZS5MZWZ0IiwgIk1FQU4uQ29uY2VudHJpYy5NZWFuLkZvcmNlLlJpZ2h0IiwgIk1FQU4uQ29uY2VudHJpYy5NZWFuLkZvcmNlLkFzeW0iLCAiTUVBTi5QZWFrLkxhbmRpbmcuRm9yY2UuQXN5bSIsICAiTUVBTi5SZWxhdGl2ZS5QZWFrLlBvd2VyIiwgIk1FQU4uQ01KLkNvbmNlbnRyaWMuRm9yY2UiLCAiTUVBTi5QZWFrLkxhbmRpbmcuRm9yY2UuTGVmdCIsICJNRUFOLlBlYWsuTGFuZGluZy5Gb3JjZS5SaWdodCIsICJEU0kiLCAiRFNJLkJ1Y2tldCIpICU+JQ0KICBtdXRhdGUoRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0ID0gJyVtLyVkLyVZJykpICU+JQ0KICBuYS5vbWl0KCkgJT4lDQogIG11dGF0ZShTcG9ydCA9ICdMYWNyb3NzZScpICAjMzMgb2JzICYgMzAgdmFycw0KYGBgDQoNCiNGb3JjZWRlY2tzIChWQUxEKSBWb2xsZXliYWxsIERhdGENCmBgYHtyfQ0KIzE6IFRFU1QgVFlQRT1DTUoNCkNNSl9WIDwtIEZvcmNlZGVja3NfViAlPiUNCiAgZmlsdGVyKFRlc3QuVHlwZT09IkNNSiIpDQoNCkNNSl9WIDwtIHN1YnNldChDTUpfViwgc2VsZWN0ID0gYygiYW5vbl9pZCIsIkRhdGUiLCJQb3NpdGlvbiIsIlRlc3QuVHlwZSIsIldlaWdodC4ua2cuIiwiQ291bnRlcm1vdmVtZW50LkRlcHRoLi5jbS4iLCJQZWFrLlBvd2VyLi4uQk0uLlcua2cuIiwiTGFuZGluZy5SRkQuLk4ucy4iLCAiRWNjZW50cmljLkNvbmNlbnRyaWMuTWVhbi5Gb3JjZS5SYXRpbyIsICJQZWFrLkxhbmRpbmcuRm9yY2UuLkFzeW0uLi5OLiIsICJQZWFrLlBvd2VyLi5XLiIsIkNvbmNlbnRyaWMuTWF4aW11bS5SRkQuLk4ucy4iLCJDb25jZW50cmljLk1heGltdW0uUkZELi5SaWdodC4uLk4ucy4iLCJDb25jZW50cmljLk1heGltdW0uUkZELi5MZWZ0Li4uTi5zLiIsIkVjY2VudHJpYy5NZWFuLkJyYWtpbmcuRm9yY2UuLk4uIiwgIk1heC5KdW1wLkhlaWdodC4uY20uIiwgIk1heC5Db25jZW50cmljLlBlYWsuRm9yY2UuLk4uIiwgIlJlbGF0aXZlLkNvbmNlbnRyaWMuUG93ZXIuQmlsYXRlcmFsIiwNCiJSZWxhdGl2ZS5FY2NlbnRyaWMuUG93ZXIuQmlsYXRlcmFsIiwiTWF4LlBlYWsuUG93ZXIuLi5CTSIsICJNYXguRWNjZW50cmljLlBlYWsuRm9yY2UuLk4uIiwNCiJNYXguUlNJLk1vZGlmaWVkLlZBTEQiLCJNYXguQ29uY2VudHJpYy5SUEQuLk4ucy4iLCAiTWF4LkNvbmNlbnRyaWMuUGVhay5WZWxvY2l0eS4ubS5zLiIsICJNYXguRWNjZW50cmljLlBlYWsuVmVsb2NpdHkuLm0ucy4iLCAiTWF4LlBlYWsuTGFuZGluZy5Gb3JjZS4uTi4iLCAiTUFYLkNvbmNlbnRyaWMuUGVhay5Qb3dlci4uVy4iLCJNYXguQ01KLkp1bXAuSGVpZ2h0Li5jbS4iLA0KIk1heC5DTUouUlNJLk1vZGlmaWVkLi5tLnMuIiwiTWF4LkNNSi5Db25jZW50cmljLlJQRC4uTi5zLiIsIk1heC5DTUouUGVhay5Qb3dlci4uVy4iLCJNYXguQ01KLlBlYWsuTGFuZGluZy5Gb3JjZS4uTi4iLCJDTUouQ29uY2VudHJpYy5SZWxhdGl2ZS5QZWFrLlBvd2VyLi4uRGlmZmVyZW5jZS5mcm9tLkZpcnN0IiwiQ01KLkVjY2VudHJpYy5SZWxhdGl2ZS5QZWFrLlBvd2VyLi4uRGlmZmVyZW5jZS5mcm9tLkZpcnN0IiwiRWNjZW50cmljLkFzeW1tZXRyeSIsIkNvbmNlbnRyaWMuQXN5bW1ldHJ5Ig0KKSkgICAgICAgICM1MzMyIG9icyAmIDM2IHZhcnMgDQoNCiNwb3NzaWJsZSBkaWZmZXJlbnQgZmluYWwgZGF0YXNldCANCmNtal92IDwtIENNSl9WICU+JQ0KICBuYS5vbWl0KCkgICM0NTcgb2JzDQoNCkNNSl9WW0NNSl9WPT0iIl0gPC0gTkENCg0KI2NvbWJpbmluZyB2YWx1ZXMgZnJvbSBkaWZmZXJlbnQgb2JzZXJ2YXRpb25zIGludG8gb25lDQpDTUpfdiA8LSBDTUpfViAlPiUNCm11dGF0ZShEYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAnJW0vJWQvJVknKSkgJT4lDQogIGZpbHRlcihUZXN0LlR5cGU9PSJDTUoiKSAlPiUgICAjYWRkIHRvIG90aGVycyBldmVuIHRobyBtaWdodCBub3QgbmVlZA0KICBncm91cF9ieShhbm9uX2lkLCBEYXRlKSAlPiUNCiAgc3VtbWFyaXNlKFdlaWdodC4ua2cuID0gbWVhbihXZWlnaHQuLmtnLiwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIENvdW50ZXJtb3ZlbWVudC5EZXB0aC4uY20uPSBtZWFuKENvdW50ZXJtb3ZlbWVudC5EZXB0aC4uY20uLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIFBlYWsuUG93ZXIuLi5CTS4uVy5rZy49IG1lYW4oUGVhay5Qb3dlci4uLkJNLi5XLmtnLiwgbmEucm09VFJVRSksDQogICAgICAgICAgICBMYW5kaW5nLlJGRC4uTi5zLj0gbWVhbihMYW5kaW5nLlJGRC4uTi5zLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIEVjY2VudHJpYy5Db25jZW50cmljLk1lYW4uRm9yY2UuUmF0aW89IG1lYW4oRWNjZW50cmljLkNvbmNlbnRyaWMuTWVhbi5Gb3JjZS5SYXRpbyxuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIFBlYWsuTGFuZGluZy5Gb3JjZS4uQXN5bS4uLk4uPSBtZWFuKFBlYWsuTGFuZGluZy5Gb3JjZS4uQXN5bS4uLk4uLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgUGVhay5Qb3dlci4uVy49IG1lYW4oUGVhay5Qb3dlci4uVy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBDb25jZW50cmljLk1heGltdW0uUkZELi5OLnMuPSBtZWFuKENvbmNlbnRyaWMuTWF4aW11bS5SRkQuLk4ucy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBDb25jZW50cmljLk1heGltdW0uUkZELi5SaWdodC4uLk4ucy49IG1lYW4oQ29uY2VudHJpYy5NYXhpbXVtLlJGRC4uUmlnaHQuLi5OLnMuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgQ29uY2VudHJpYy5NYXhpbXVtLlJGRC4uTGVmdC4uLk4ucy49IG1lYW4oQ29uY2VudHJpYy5NYXhpbXVtLlJGRC4uTGVmdC4uLk4ucy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBFY2NlbnRyaWMuTWVhbi5CcmFraW5nLkZvcmNlLi5OLj0gbWVhbihFY2NlbnRyaWMuTWVhbi5CcmFraW5nLkZvcmNlLi5OLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5KdW1wLkhlaWdodC4uY20uPSBtZWFuKE1heC5KdW1wLkhlaWdodC4uY20uLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkNvbmNlbnRyaWMuUGVhay5Gb3JjZS4uTi49IG1lYW4oTWF4LkNvbmNlbnRyaWMuUGVhay5Gb3JjZS4uTi4sbmEucm09VFJVRSksDQogICAgICAgICAgICBSZWxhdGl2ZS5Db25jZW50cmljLlBvd2VyLkJpbGF0ZXJhbD0gbWVhbihSZWxhdGl2ZS5Db25jZW50cmljLlBvd2VyLkJpbGF0ZXJhbCxuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIFJlbGF0aXZlLkVjY2VudHJpYy5Qb3dlci5CaWxhdGVyYWw9IG1lYW4oUmVsYXRpdmUuRWNjZW50cmljLlBvd2VyLkJpbGF0ZXJhbCxuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5QZWFrLlBvd2VyLi4uQk09IG1lYW4oTWF4LlBlYWsuUG93ZXIuLi5CTSxuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5FY2NlbnRyaWMuUGVhay5Gb3JjZS4uTi49IG1lYW4oTWF4LkVjY2VudHJpYy5QZWFrLkZvcmNlLi5OLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5SU0kuTW9kaWZpZWQuVkFMRD0gbWVhbihNYXguUlNJLk1vZGlmaWVkLlZBTEQsbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguQ29uY2VudHJpYy5SUEQuLk4ucy49IG1lYW4oTWF4LkNvbmNlbnRyaWMuUlBELi5OLnMuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkNvbmNlbnRyaWMuUGVhay5WZWxvY2l0eS4ubS5zLj0gbWVhbihNYXguQ29uY2VudHJpYy5QZWFrLlZlbG9jaXR5Li5tLnMuLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkVjY2VudHJpYy5QZWFrLlZlbG9jaXR5Li5tLnMuPSBtZWFuKE1heC5FY2NlbnRyaWMuUGVhay5WZWxvY2l0eS4ubS5zLixuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIE1heC5QZWFrLkxhbmRpbmcuRm9yY2UuLk4uPSBtZWFuKE1heC5QZWFrLkxhbmRpbmcuRm9yY2UuLk4uLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTUFYLkNvbmNlbnRyaWMuUGVhay5Qb3dlci4uVy49IG1lYW4oTUFYLkNvbmNlbnRyaWMuUGVhay5Qb3dlci4uVy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguQ01KLkp1bXAuSGVpZ2h0Li5jbS49IG1lYW4oTWF4LkNNSi5KdW1wLkhlaWdodC4uY20uLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgTWF4LkNNSi5SU0kuTW9kaWZpZWQuLm0ucy49IG1lYW4oTWF4LkNNSi5SU0kuTW9kaWZpZWQuLm0ucy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguQ01KLkNvbmNlbnRyaWMuUlBELi5OLnMuPSBtZWFuKE1heC5DTUouQ29uY2VudHJpYy5SUEQuLk4ucy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguQ01KLlBlYWsuUG93ZXIuLlcuPSBtZWFuKE1heC5DTUouUGVhay5Qb3dlci4uVy4sbmEucm09VFJVRSksDQogICAgICAgICAgICBNYXguQ01KLlBlYWsuTGFuZGluZy5Gb3JjZS4uTi49IG1lYW4oTWF4LkNNSi5QZWFrLkxhbmRpbmcuRm9yY2UuLk4uLG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgQ01KLkNvbmNlbnRyaWMuUmVsYXRpdmUuUGVhay5Qb3dlci4uLkRpZmZlcmVuY2UuZnJvbS5GaXJzdD0gbWVhbihDTUouQ29uY2VudHJpYy5SZWxhdGl2ZS5QZWFrLlBvd2VyLi4uRGlmZmVyZW5jZS5mcm9tLkZpcnN0LG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgQ01KLkVjY2VudHJpYy5SZWxhdGl2ZS5QZWFrLlBvd2VyLi4uRGlmZmVyZW5jZS5mcm9tLkZpcnN0PSBtZWFuKENNSi5FY2NlbnRyaWMuUmVsYXRpdmUuUGVhay5Qb3dlci4uLkRpZmZlcmVuY2UuZnJvbS5GaXJzdCxuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIFBvc2l0aW9uPSBnZXRfbW9kZShQb3NpdGlvbiksDQogICAgICAgICAgICBFY2NlbnRyaWMuQXN5bW1ldHJ5PSBnZXRfbW9kZShFY2NlbnRyaWMuQXN5bW1ldHJ5KSwNCiAgICAgICAgICAgIENvbmNlbnRyaWMuQXN5bW1ldHJ5PSBnZXRfbW9kZShDb25jZW50cmljLkFzeW1tZXRyeSksDQogICAgICAgICAgICAuZ3JvdXBzID0gJ2Ryb3AnDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgKSAgICAgICAgICMgMTQxNiBvYnMgJiAzMiB2YXJzIC0+IDE4MDEgb2JzIHcvIFBvc2l0aW9uIEVjY2VudHJpYyArIENvbmNlbnRyaWMgQXN5bW1ldHJ5DQoNCkNNSl92YiA8LSBDTUpfdiAlPiUNCiAgbmEub21pdCgpICAgIzUwOCBvYnMgJiAzMiB2YXJzICAtPiAxNzMgb2JzIHcvIFBvc2l0aW9uIEVjY2VudHJpYyArIENvbmNlbnRyaWMgQXN5bW1ldHJ5DQpgYGANCg0KYGBge3J9DQojc2VsZWN0cyBjb3VudGVyIG1vdmVtZW50IGp1bXBzIGFub3RoZXIgd2F5IHdpdGggbm9ybWF0aXZlIGluZm9ybWF0aW9uDQp2IDwtIEZvcmNlZGVja3NfViAlPiUNCiAgZmlsdGVyKFRlc3QuVHlwZSA9PSAnQ01KJykgJT4lDQogIGRwbHlyOjpzZWxlY3QoImFub25faWQiLCJEYXRlIiwiUG9zaXRpb24iLCJUZXN0LlR5cGUiLCJDb3VudGVybW92ZW1lbnQuRGVwdGguLmNtLiIsIlBlYWsuUG93ZXIuLi5CTS4uVy5rZy4iLCJMYW5kaW5nLlJGRC4uTi5zLiIsICJFY2NlbnRyaWMuQ29uY2VudHJpYy5NZWFuLkZvcmNlLlJhdGlvIiwgIlBlYWsuTGFuZGluZy5Gb3JjZS4uQXN5bS4uLk4uIiwgIlBlYWsuUG93ZXIuLlcuIiwgIkNvbmNlbnRyaWMuUkZELi5OLnMuIiwgIkNvbmNlbnRyaWMuUkZELi5MZWZ0Li4uTi5zLiIsIkNvbmNlbnRyaWMuUkZELi5SaWdodC4uLk4ucy4iLCAiQ29uY2VudHJpYy5UaW1lLnRvLlBlYWsuRm9yY2UuLnMuIiwgIkVjY2VudHJpYy5NZWFuLkJyYWtpbmcuRm9yY2UuLk4uIiwgIkxhbmRpbmcuTmV0LlBlYWsuRm9yY2UuLi5CTS4uTi5rZy4iLCAiUGVhay5OZXQuVGFrZW9mZi5Gb3JjZS4uLkJNLi5OLmtnLiIsICJDb25jZW50cmljLlJQRC4uLkJNLi5XLnMua2cuIiwgIkZvcmNlLmF0LlBlYWsuUG93ZXIuLk4uIiwgIkVjY2VudHJpYy5NZWFuLkRlY2VsZXJhdGlvbi5Gb3JjZS4uTi4iLCAiRWNjZW50cmljLlBlYWsuRm9yY2UuLk4uIiwgIlJTSS5Nb2RpZmllZC4ubS5zLiIsICJDTUouU3RpZmZuZXNzLi5MZWZ0Li4uTi5tLiIsICJDTUouU3RpZmZuZXNzLi5SaWdodC4uLk4ubS4iLCAiRWNjZW50cmljLkFzeW1tZXRyeSIsIkNvbmNlbnRyaWMuQXN5bW1ldHJ5IiwgIlBlYWsuTGFuZGluZy5Bc3ltbWV0cnkiLCAiRFNJIiwgIkRTSS5CdWNrZXQiLCAiRWNjZW50cmljLlBlYWsuUG93ZXIuLi5CTS4uVy5rZy4iLCAiSnVtcC5IZWlnaHQuLkltcC5Nb20uLi5jbS4iLCAiRWNjZW50cmljLkR1cmF0aW9uLi5zLiIsICJFY2NlbnRyaWMuRGVjZWxlcmF0aW9uLkltcHVsc2UuLk5zLiIpICU+JQ0KICBuYS5vbWl0KCkNCg0KI2NhbGN1bGF0ZXMgZGlmZmVyZW5jZXMgZnJvbSBub3JtIGFuZCBtYWtlcyBEYXRlIGEgZGF0ZSBvYmplY3QNCnYgPC0gdiAlPiUNCiAgbXV0YXRlKERhdGUgPSBhcy5EYXRlKERhdGUsIGZvcm1hdCA9ICclbS8lZC8lWScpLA0KICAgICAgICAgUlNJLk1vZGlmaWVkLi5tLnMuID0gUlNJLk1vZGlmaWVkLi5tLnMuIC8gMTAwLA0KICAgICAgICAgUlNJLk1vZGlmaWVkLkRpZmYuTm9ybSA9IChSU0kuTW9kaWZpZWQuLm0ucy4gLSAwLjQyMSkgLyAwLjQyMSwNCiAgICAgICAgIEVjYy5QZWFrLlBvd2VyLlJlbC5EaWZmLk5vcm0gPSAoRWNjZW50cmljLlBlYWsuUG93ZXIuLi5CTS4uVy5rZy4gLSAxOCkgLyAxOCwNCiAgICAgICAgIEp1bXAuSGVpZ2guRGlmZi5Ob3JtID0gKEp1bXAuSGVpZ2h0Li5JbXAuTW9tLi4uY20uIC0gMzMpIC8gMzMsDQogICAgICAgICBFY2MuRHVyYXRpb24uRGlmZi5Ob3JtID0gKEVjY2VudHJpYy5EdXJhdGlvbi4ucy4gLSAwLjUyKSAvIDAuNTIsDQogICAgICAgICBFY2MuRGVjZWxlcmF0aW9uLkltcHVsc2UuRGlmZi5Ob3JtID0gKEVjY2VudHJpYy5EZWNlbGVyYXRpb24uSW1wdWxzZS4uTnMuIC0gOTYuMCkgLyA5Ni4wLA0KICAgICAgICAgU3BvcnQgPSAnVm9sbGV5YmFsbCcNCiAgKQ0KYGBgDQoNCmBgYHtyfQ0KIzI6VEVTVCBUWVBFPSBJTVRQDQpJTVRQX1YgPC0gRm9yY2VkZWNrc19WICU+JQ0KICBmaWx0ZXIoVGVzdC5UeXBlPT0iSU1UUCIpICU+JSAjMTI0MQ0KICBzZWxlY3QoImFub25faWQiLCAiRGF0ZSIsICJCYXNlbGluZS5Gb3JjZS4uTi4iLCJCYXNlbGluZS5Gb3JjZS4uQXN5bS4uLk4uIiwgIlBlYWsuVmVydGljYWwuRm9yY2UuLk4uIiwgIlBlYWsuVmVydGljYWwuRm9yY2UuLi5CTS4uTi5rZy4iLCAiUGVhay5WZXJ0aWNhbC5Gb3JjZS4uQXN5bS4uLk4uIiwgIlJGRC4uLjUwbXMuLk4ucy4iLCAiUkZELi4uNTBtcy4uQXN5bS4uLk4ucy4iLCAiUkZELi4uMTAwbXMuLk4ucy4iLCAiUkZELi4uMTAwbXMuLkFzeW0uLi5OLnMuIiwgIlJGRC4uLjE1MG1zLi5OLnMuIiwgIlJGRC4uLjE1MG1zLi5Bc3ltLi4uTi5zLiIsICJSRkQuLi4yMDBtcy4uTi5zLiIsICJSRkQuLi4yMDBtcy4uQXN5bS4uLk4ucy4iLCAiTmV0LlBlYWsuVmVydGljYWwuRm9yY2UuLk4ucy4iLCAiTmV0LlBlYWsuVmVydGljYWwuRm9yY2UuLkFzeW0uLi5OLnMuIiwgIkZvcmNlLmF0LjIwMG1zLi4uQk0uLk4ua2cuIiwgIkVjY2VudHJpYy5Bc3ltbWV0cnkiLCAiQ29uY2VudHJpYy5Bc3ltbWV0cnkiLCJNRUFOLkVjY2VudHJpYy5NZWFuLkZvcmNlLkxlZnQiLCAiTUVBTi5FY2NlbnRyaWMuTWVhbi5Gb3JjZS5SaWdodCIsICJNRUFOLkNvbmNlbnRyaWMuTWVhbi5Gb3JjZS5MZWZ0IiwgIk1FQU4uQ29uY2VudHJpYy5NZWFuLkZvcmNlLlJpZ2h0IiwgIk1FQU4uQ29uY2VudHJpYy5NZWFuLkZvcmNlLkFzeW0iLCAiTUVBTi5QZWFrLkxhbmRpbmcuRm9yY2UuQXN5bSIsICAiTUVBTi5SZWxhdGl2ZS5QZWFrLlBvd2VyIiwgIk1FQU4uQ01KLkNvbmNlbnRyaWMuRm9yY2UiLCAiTUVBTi5QZWFrLkxhbmRpbmcuRm9yY2UuTGVmdCIsICJNRUFOLlBlYWsuTGFuZGluZy5Gb3JjZS5SaWdodCIsICJEU0kiLCAiRFNJLkJ1Y2tldCIpICU+JQ0KICBtdXRhdGUoRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0ID0gJyVtLyVkLyVZJykpICU+JQ0KICBuYS5vbWl0KCkgJT4lDQogIG11dGF0ZShTcG9ydCA9ICdWb2xsZXliYWxsJykgICMyNDkgb2JzICYgMzAgdmFycw0KYGBgDQoNCmBgYHtyfQ0KIzM6IFRFU1QgVFlQRT0gSEoNCkhKX1YgPC0gRm9yY2VkZWNrc19WICU+JQ0KICBmaWx0ZXIoVGVzdC5UeXBlPT0iSEoiKSAgJT4lICAjMzY3IG9icw0KICBkcGx5cjo6c2VsZWN0KCJhbm9uX2lkIiwgIkRhdGUiLCAiQ29ycmVjdGVkLlN0YW5kaW5nLldlaWdodC4uS2cuIiwgIk1lYW4uUlNJLi5GbGlnaHQuQ29udGFjdC5UaW1lLiIsICJBY3RpdmUuU3RpZmZuZXNzLi5OLm0uIiwgIkJlc3QuQXZlcmFnZS5Gb3JjZS4uTi4iLCAiQmVzdC5BdmVyYWdlLkZvcmNlLi5Bc3ltLi4uTi4iLCAiQmVzdC5UaW1lLnRvLlBlYWsuRm9yY2UuLm1zLiIsICJCZXN0LkNvbnRhY3QuVGltZS4ubXMuIiwgIkJlc3QuRmxpZ2h0LlRpbWUuLm1zLiIsICJCZXN0LkltcHVsc2UuLk4ucy4iLCAiQmVzdC5QZWFrLkZvcmNlLi5OLiIsICJCZXN0LlBlYWsuRm9yY2UuLkFzeW0uLi5OLiIsICJNZWFuLkF2ZXJhZ2UuRm9yY2UuLk4uIiwgIk1lYW4uQXZlcmFnZS5Gb3JjZS4uQXN5bS4uLk4uIiwgIk1lYW4uTGFuZGluZy5SRkQuLk4ucy4iLCAiTWVhbi5MYW5kaW5nLlJGRC4uQXN5bS4uLk4ucy4iLCAiU3RpZmZuZXNzLkZhdGlndWUuLi4uIiwgIlN0aWZmbmVzcy5GYXRpZ3VlLi5Bc3ltLi4uLi4iLCAiTWF4Lkp1bXAuSGVpZ2h0Li5jbS4iLCAiSEouUlNJIiwgIk1lYW4uRmxpZ2h0LlRpbWUuLm1zLiIsICJNZWFuLkNvbnRhY3QuVGltZS4ubXMuIikgJT4lDQogIG11dGF0ZShEYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAnJW0vJWQvJVknKSkgJT4lDQogIG5hLm9taXQoKSAlPiUNCiAgbXV0YXRlKFNwb3J0ID0gJ1ZvbGxleWJhbGwnKQ0KICAgICAgICAgICAgICAgICAjMzUyIG9icyAmIDIwIHZhcnMNCmBgYA0KDQo0LiBQZXJmb3JtYW5jZSBkYXRhc2V0cw0KT2YgYWxsIHBlcmZvcm1hbmNlIGRhdGFzZXRzLCBvbmx5IGJhc2tldGJhbGwgYW5kIHZvbGxleWJhbGwgaGF2ZSBwb3NpdGlvbmFsIG5vcm0gaW5mb3JtYXRpb24gYnV0IGFyZSBhbHNvIG1pc3NpbmcgYSBsb3Qgb2YgcG9zaXRpb25hbCBpbmZvcm1hdGlvbiB3aGljaCBtYWtlcyB0aGlzIGNvbHVtbiBzcGFyc2UuIE5vbmUgb2YgdGhlIGRhdGFzZXRzIGNvbnRhaW4gcm90YXRpb25hbCBkYXRhIG9yIHJhem9yIGRhdGEuIENvbnRhaW4gc21hbGwgYW1vdW50cyBvZiBpc28gcHJvbmUgZGF0YS4gDQoNCiNQZXJmb3JtYW5jZSAoVkFMRCkgQmFza2V0YmFsbCBEYXRhDQpgYGB7cn0NCiNzZWxlY3RzIHZhcmlhYmxlcyBvZiBpbnRlcmVzdCwgbm9yZGljIGFuZCBoaXAgZGF0YSwgYW5kIGNsZWFucyB1cCBwb3NpdGlvbiB2YXJpYWJsZQ0KcGVyZm9ybWFuY2VfQiA8LSBzdWJzZXQoUGVyZm9ybWFuY2VfQiwgc2VsZWN0ID0gYygnYW5vbl9pZCcsICdEYXRlJywgJ0F0aGxldGUuQm9keXdlaWdodC4ua2cuJywnU3BvcnQuUG9zaXRpb24nLCAnU2lkZScsICdSZXBldGl0aW9ucycsICdNYXhpbXVtLkZvcmNlJywgJ0F2ZXJhZ2UuRm9yY2UnLCAnSW1wdWxzZScsICdOb3JkaWMuTGVmdC5NRUFOJywgJ05vcmRpYy5SaWdodC5NRUFOJywgJ05vcmRpYy5NRUFOLkltYmFsYW5jZScsICdOb3JkaWMuTGVmdC5NQVgnLCAnTm9yZGljLlJpZ2h0Lk1BWCcsICdOb3JkaWMuTUFYLkltYmFsYW5jZScsICdUcmVuZCcsICdOb3JkaWMuLi5EaWZmZXJlbmNlLmZyb20uRmlyc3QuVGVzdCcsICdNYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbicsICdSZWxhdGl2ZS5NYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbicsICdIaXAuQWJkLkxlZnQuTUVBTicsICdIaXAuQWJkLlJpZ2h0Lk1FQU4nLCAnSGlwLkFiZHVjdGlvbi5NRUFOLkltYmFsYW5jZScsICdIaXAuQWJkLkxlZnQuTUFYJywgJ0hpcC5BYmQuUmlnaHQuTUFYJywgJ0hpcC5BYmR1Y3Rpb24uTUFYLkltYmFsYW5jZScsICdIaXAuQWRkLkxlZnQuTUVBTicsICdIaXAuQWRkLlJpZ2h0Lk1FQU4nLCAnSGlwLkFkZHVjdGlvbi5NRUFOLkltYmFsYW5jZScsICdIaXAuQWRkLkxlZnQuTUFYJywgJ0hpcC5BZGQuUmlnaHQuTUFYJywgJ0hpcC5BZGR1Y3Rpb24uTUFYLkltYmFsYW5jZScsICdCaWxhdGVyYWwuSGlwLkFiZHVjdGlvbi5BZGR1Y3Rpb24uUmF0aW8nKSkgJT4lDQogIG11dGF0ZShQb3NpdGlvbiA9IGNhc2Vfd2hlbigNCiAgICBTcG9ydC5Qb3NpdGlvbiA9PSAnJyB+ICdOb25lJywNCiAgICBTcG9ydC5Qb3NpdGlvbiA9PSAnfEd1YXJkJyB+ICdHdWFyZCcsDQogICAgc3RyX2RldGVjdChTcG9ydC5Qb3NpdGlvbiwgIlByaW1hcnk6IikgfiAnRm9yd2FyZCcsDQogICAgVFJVRSB+IFNwb3J0LlBvc2l0aW9uDQogICkpICU+JQ0KICBkcGx5cjo6c2VsZWN0KC1TcG9ydC5Qb3NpdGlvbikNCg0KI21ha2VzIHRoZSBkYXRlIGNvbHVtbiBhICdkYXRlJyBvYmplY3QgZm9yIGxhdGVyIGFuZCBvbWl0cyBOQSB2YWx1ZXMgZm9yIG5vcmRpYyBkYXRhc2V0DQpwZXJmb3JtYW5jZV9CX25vcmRpYyA8LSBwZXJmb3JtYW5jZV9CICU+JQ0KICBkcGx5cjo6c2VsZWN0KC1jKCdIaXAuQWJkLkxlZnQuTUVBTicsICdIaXAuQWJkLlJpZ2h0Lk1FQU4nLCAnSGlwLkFiZHVjdGlvbi5NRUFOLkltYmFsYW5jZScsICdIaXAuQWJkLkxlZnQuTUFYJywgJ0hpcC5BYmQuUmlnaHQuTUFYJywgJ0hpcC5BYmR1Y3Rpb24uTUFYLkltYmFsYW5jZScsICdIaXAuQWRkLkxlZnQuTUVBTicsICdIaXAuQWRkLlJpZ2h0Lk1FQU4nLCAnSGlwLkFkZHVjdGlvbi5NRUFOLkltYmFsYW5jZScsICdIaXAuQWRkLkxlZnQuTUFYJywgJ0hpcC5BZGQuUmlnaHQuTUFYJywgJ0hpcC5BZGR1Y3Rpb24uTUFYLkltYmFsYW5jZScsICdCaWxhdGVyYWwuSGlwLkFiZHVjdGlvbi5BZGR1Y3Rpb24uUmF0aW8nKSkgJT4lDQogIGZpbHRlcihBdGhsZXRlLkJvZHl3ZWlnaHQuLmtnLiA+IDUpICU+JQ0KICBtdXRhdGUoRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0ID0gJyVtLyVkLyVZJyksDQogICAgICAgICBGb3JjZS5EaWZmLk5vcm0gPSAoTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4gLSAzMDgpIC8gMzA4LA0KICAgICAgICAgSW1iYWxhbmNlLkRpZmYuTm9ybSA9IChOb3JkaWMuTUVBTi5JbWJhbGFuY2UgLSA2LjMpIC8gNi4zLA0KICAgICAgICAgU3BvcnQgPSAnQmFza2V0YmFsbCcpICU+JQ0KICBuYS5vbWl0KCkNCg0KI21ha2VzIHRoZSBkYXRlIGNvbHVtbiBhICdkYXRlJyBvYmplY3QgZm9yIGxhdGVyIGFuZCBvbWl0cyBOQSB2YWx1ZXMgZm9yIGhpcCBkYXRhc2V0DQpwZXJmb3JtYW5jZV9CX2hpcCA8LSBwZXJmb3JtYW5jZV9CICU+JQ0KICBkcGx5cjo6c2VsZWN0KC1jKCdOb3JkaWMuTGVmdC5NRUFOJywgJ05vcmRpYy5SaWdodC5NRUFOJywgJ05vcmRpYy5NRUFOLkltYmFsYW5jZScsICdOb3JkaWMuTGVmdC5NQVgnLCAnTm9yZGljLlJpZ2h0Lk1BWCcsICdOb3JkaWMuTUFYLkltYmFsYW5jZScsICdUcmVuZCcsICdOb3JkaWMuLi5EaWZmZXJlbmNlLmZyb20uRmlyc3QuVGVzdCcsICdNYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbicsICdSZWxhdGl2ZS5NYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbicpKSAlPiUNCiAgZmlsdGVyKEF0aGxldGUuQm9keXdlaWdodC4ua2cuID4gNSkgJT4lDQogIG11dGF0ZShEYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAnJW0vJWQvJVknKSwNCiAgICAgICAgIEFiZC5BZGQuUmF0aW8uRGlmZi5Ob3JtID0gKEJpbGF0ZXJhbC5IaXAuQWJkdWN0aW9uLkFkZHVjdGlvbi5SYXRpbyAtIDEpIC8gMSwNCiAgICAgICAgIFNwb3J0ID0gJ0Jhc2tldGJhbGwnKSAlPiUNCiAgbmEub21pdCgpDQpgYGANCg0KTmVlZCB0byBlaXRoZXIgZ2V0IG1vcmUgZGF0YSBvbiBwb3NpdGlvbnMgb2YgcGxheWVycyBvciBnZXQgcmlkIG9mIHBlcmNlbnQgZGlmZmVyZW5jZSBmcm9tIG5vcm0gc2luY2UgaXQgaGFzIGEgbG90IG9mIE5Bcy4gQ291bGQgY29uc2lkZXIgYXRobGV0ZSBib2R5d2VpZ2h0IGFzIHdlbGwgdG8gcHV0IHN0cmVuZ3RoIHJlbGF0aXZlbHkgYnV0IGFsc28gaGFzIG1pc3NpbmcgZGF0YSBhbmQgaGFzIG5lZ2F0aXZlIHZhbHVlcz8gQWxzbyBtaXNzaW5nIGEgZGVjZW50IGFtb3VudCBvZiB6LXNjb3JlIG9ic2VydmF0aW9ucy4gMTQ3IG9ic2VydmF0aW9ucyB3aXRoIHBlcmNlbnQgZGlmZmVyZW5jZSBub3JtIGFuZCB6LXNjb3Jlcy4gNTUwIHdpdGggb25seSB6LXNjb3Jlcy4gNTkyIHdpdGggbmVpdGhlciBwZXJjZW50IGRpZmZlcmVuY2Ugbm9ybSBvciB6LXNjb3Jlcy4gSWYgd2UgaW5jbHVkZSBhdGhsZXRlIGJvZHl3ZWlnaHQgYW5kIGV4Y2x1ZGUgcGVyY2VudCBkaWZmZXJlbmNlIG5vcm0gYW5kIHotc2NvcmVzIHRoZXJlIGFyZSA1MjEgb2JzZXJ2YXRpb25zLiANCg0KSGlwIGRhdGFzZXQgY29udGFpbnMgMTA5IG9ic2VydmF0aW9ucyBpbmNsdWRpbmcgdGhlIGJvZHl3ZWlnaHQgdmFyaWFibGUsIDEyOSBvdGhlcndpc2UuIA0KDQojUGVyZm9ybWFuY2UgKFZBTEQpIFNvY2NlciBEYXRhDQpgYGB7cn0NCiNzZWxlY3RzIHZhcmlhYmxlcyBvZiBpbnRlcmVzdCwgbm9yZGljIGFuZCBoaXAgZGF0YSwgYW5kIGNsZWFucyB1cCBwb3NpdGlvbiB2YXJpYWJsZQ0KcGVyZm9ybWFuY2VfUyA8LSBzdWJzZXQoUGVyZm9ybWFuY2VfUywgc2VsZWN0ID0gYygnYW5vbl9pZCcsICdEYXRlJywgJ0F0aGxldGUuQm9keXdlaWdodC4ua2cuJywnU3BvcnQuUG9zaXRpb24nLCAnU2lkZScsICdSZXBldGl0aW9ucycsICdNYXhpbXVtLkZvcmNlJywgJ0F2ZXJhZ2UuRm9yY2UnLCAnSW1wdWxzZScsICdOb3JkaWMuTGVmdC5NRUFOJywgJ05vcmRpYy5SaWdodC5NRUFOJywgJ05vcmRpYy5NRUFOLkltYmFsYW5jZScsICdOb3JkaWMuTGVmdC5NQVgnLCAnTm9yZGljLlJpZ2h0Lk1BWCcsICdOb3JkaWMuTUFYLkltYmFsYW5jZScsICdUcmVuZCcsICdOb3JkaWMuLi5EaWZmZXJlbmNlLmZyb20uRmlyc3QuVGVzdCcsICdNYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbicsICdSZWxhdGl2ZS5NYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbicsICdIaXAuQWJkLkxlZnQuTUVBTicsICdIaXAuQWJkLlJpZ2h0Lk1FQU4nLCAnSGlwLkFiZHVjdGlvbi5NRUFOLkltYmFsYW5jZScsICdIaXAuQWJkLkxlZnQuTUFYJywgJ0hpcC5BYmQuUmlnaHQuTUFYJywgJ0hpcC5BYmR1Y3Rpb24uTUFYLkltYmFsYW5jZScsICdIaXAuQWRkLkxlZnQuTUVBTicsICdIaXAuQWRkLlJpZ2h0Lk1FQU4nLCAnSGlwLkFkZHVjdGlvbi5NRUFOLkltYmFsYW5jZScsICdIaXAuQWRkLkxlZnQuTUFYJywgJ0hpcC5BZGQuUmlnaHQuTUFYJywgJ0hpcC5BZGR1Y3Rpb24uTUFYLkltYmFsYW5jZScsICdCaWxhdGVyYWwuSGlwLkFiZHVjdGlvbi5BZGR1Y3Rpb24uUmF0aW8nKSkgJT4lDQogIG11dGF0ZShQb3NpdGlvbiA9IGNhc2Vfd2hlbigNCiAgICBTcG9ydC5Qb3NpdGlvbiA9PSAnJyB+ICdOb25lJywNCiAgICBUUlVFIH4gU3BvcnQuUG9zaXRpb24NCiAgKSkgJT4lDQogIGRwbHlyOjpzZWxlY3QoLVNwb3J0LlBvc2l0aW9uKQ0KDQojbWFrZXMgdGhlIGRhdGUgY29sdW1uIGEgJ2RhdGUnIG9iamVjdCBmb3IgbGF0ZXIgYW5kIG9taXRzIE5BIHZhbHVlcyBmb3Igbm9yZGljIGRhdGFzZXQNCnBlcmZvcm1hbmNlX1Nfbm9yZGljIDwtIHBlcmZvcm1hbmNlX1MgJT4lDQogIGRwbHlyOjpzZWxlY3QoLWMoJ0hpcC5BYmQuTGVmdC5NRUFOJywgJ0hpcC5BYmQuUmlnaHQuTUVBTicsICdIaXAuQWJkdWN0aW9uLk1FQU4uSW1iYWxhbmNlJywgJ0hpcC5BYmQuTGVmdC5NQVgnLCAnSGlwLkFiZC5SaWdodC5NQVgnLCAnSGlwLkFiZHVjdGlvbi5NQVguSW1iYWxhbmNlJywgJ0hpcC5BZGQuTGVmdC5NRUFOJywgJ0hpcC5BZGQuUmlnaHQuTUVBTicsICdIaXAuQWRkdWN0aW9uLk1FQU4uSW1iYWxhbmNlJywgJ0hpcC5BZGQuTGVmdC5NQVgnLCAnSGlwLkFkZC5SaWdodC5NQVgnLCAnSGlwLkFkZHVjdGlvbi5NQVguSW1iYWxhbmNlJywgJ0JpbGF0ZXJhbC5IaXAuQWJkdWN0aW9uLkFkZHVjdGlvbi5SYXRpbycpKSAlPiUNCiAgZmlsdGVyKEF0aGxldGUuQm9keXdlaWdodC4ua2cuID4gNSkgJT4lDQogIG11dGF0ZShEYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAnJW0vJWQvJVknKSwNCiAgICAgICAgIEZvcmNlLkRpZmYuTm9ybSA9IChNYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbiAtIDI5OCkgLyAyOTgsDQogICAgICAgICBJbWJhbGFuY2UuRGlmZi5Ob3JtID0gKE5vcmRpYy5NRUFOLkltYmFsYW5jZSAtIDYuNSkgLyA2LjUsDQogICAgICAgICBTcG9ydCA9ICdTb2NjZXInKSAlPiUNCiAgbmEub21pdCgpDQoNCiNtYWtlcyB0aGUgZGF0ZSBjb2x1bW4gYSAnZGF0ZScgb2JqZWN0IGZvciBsYXRlciBhbmQgb21pdHMgTkEgdmFsdWVzIGZvciBoaXAgZGF0YXNldA0KcGVyZm9ybWFuY2VfU19oaXAgPC0gcGVyZm9ybWFuY2VfUyAlPiUNCiAgZHBseXI6OnNlbGVjdCgtYygnTm9yZGljLkxlZnQuTUVBTicsICdOb3JkaWMuUmlnaHQuTUVBTicsICdOb3JkaWMuTUVBTi5JbWJhbGFuY2UnLCAnTm9yZGljLkxlZnQuTUFYJywgJ05vcmRpYy5SaWdodC5NQVgnLCAnTm9yZGljLk1BWC5JbWJhbGFuY2UnLCAnVHJlbmQnLCAnTm9yZGljLi4uRGlmZmVyZW5jZS5mcm9tLkZpcnN0LlRlc3QnLCAnTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4nLCAnUmVsYXRpdmUuTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4nKSkgJT4lDQogIGZpbHRlcihBdGhsZXRlLkJvZHl3ZWlnaHQuLmtnLiA+IDUpICU+JQ0KICBtdXRhdGUoRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0ID0gJyVtLyVkLyVZJyksDQogICAgICAgICBBYmQuQWRkLlJhdGlvLkRpZmYuTm9ybSA9IChCaWxhdGVyYWwuSGlwLkFiZHVjdGlvbi5BZGR1Y3Rpb24uUmF0aW8gLSAwLjk4KSAvIDAuOTgsDQogICAgICAgICBTcG9ydCA9ICdTb2NjZXInKSAlPiUNCiAgbmEub21pdCgpDQpgYGANCg0KRG9lcyBub3QgY29udGFpbiBhbnkgaW5mb3JtYXRpb24gYWJvdXQgcG9zaXRpb25hbCBub3JtcyBzbyB0aGVyZSBhcmUgbm8gcGVyY2VudCBkaWZmZXJlbmNlcyBmcm9tIG5vcm0uIDQyMSBvYnNlcnZhdGlvbnMgd2l0aCB6LXNjb3Jlcy4gNDgzIG9ic2VydmF0aW9ucyB3aXRob3V0IHotc2NvcmVzLiBUaGVyZSBhcmUgNDAwIG9ic2VydmF0aW9ucyBpZiBib2R5d2VpZ2h0IGlzIGluY2x1ZGVkLiAgDQoNCkhpcCBkYXRhc2V0IGNvbnRhaW5zIG9ubHkgMzkgb2JzZXJ2YXRpb25zIHdpdGggYm9keSB3ZWlnaHQgaW5jbHVkZWQgYW5kIHdpdGhvdXQgaXQgaW5jbHVkZWQuIA0KDQojUGVyZm9ybWFuY2UgKFZBTEQpIExhY3Jvc3NlIERhdGENCmBgYHtyfQ0KI3NlbGVjdHMgdmFyaWFibGVzIG9mIGludGVyZXN0LCBub3JkaWMgYW5kIGhpcCBkYXRhLCBhbmQgY2xlYW5zIHVwIHBvc2l0aW9uIHZhcmlhYmxlDQpwZXJmb3JtYW5jZV9MIDwtIHN1YnNldChQZXJmb3JtYW5jZV9MLCBzZWxlY3QgPSBjKCdhbm9uX2lkJywgJ0RhdGUnLCAnQXRobGV0ZS5Cb2R5d2VpZ2h0Li5rZy4nLCdTcG9ydC5Qb3NpdGlvbicsICdTaWRlJywgJ1JlcGV0aXRpb25zJywgJ01heGltdW0uRm9yY2UnLCAnQXZlcmFnZS5Gb3JjZScsICdJbXB1bHNlJywgJ05vcmRpYy5MZWZ0Lk1FQU4nLCAnTm9yZGljLlJpZ2h0Lk1FQU4nLCAnTm9yZGljLk1FQU4uSW1iYWxhbmNlJywgJ05vcmRpYy5MZWZ0Lk1BWCcsICdOb3JkaWMuUmlnaHQuTUFYJywgJ05vcmRpYy5NQVguSW1iYWxhbmNlJywgJ1RyZW5kJywgJ05vcmRpYy4uLkRpZmZlcmVuY2UuZnJvbS5GaXJzdC5UZXN0JywgJ01heGltdW0uTm9yZGljLkJpbGF0ZXJhbC5NZWFuJywgJ1JlbGF0aXZlLk1heGltdW0uTm9yZGljLkJpbGF0ZXJhbC5NZWFuJywgJ0hpcC5BYmQuTGVmdC5NRUFOJywgJ0hpcC5BYmQuUmlnaHQuTUVBTicsICdIaXAuQWJkdWN0aW9uLk1FQU4uSW1iYWxhbmNlJywgJ0hpcC5BYmQuTGVmdC5NQVgnLCAnSGlwLkFiZC5SaWdodC5NQVgnLCAnSGlwLkFiZHVjdGlvbi5NQVguSW1iYWxhbmNlJywgJ0hpcC5BZGQuTGVmdC5NRUFOJywgJ0hpcC5BZGQuUmlnaHQuTUVBTicsICdIaXAuQWRkdWN0aW9uLk1FQU4uSW1iYWxhbmNlJywgJ0hpcC5BZGQuTGVmdC5NQVgnLCAnSGlwLkFkZC5SaWdodC5NQVgnLCAnSGlwLkFkZHVjdGlvbi5NQVguSW1iYWxhbmNlJywgJ0JpbGF0ZXJhbC5IaXAuQWJkdWN0aW9uLkFkZHVjdGlvbi5SYXRpbycpKSAlPiUNCiAgbXV0YXRlKFBvc2l0aW9uID0gY2FzZV93aGVuKA0KICAgIFNwb3J0LlBvc2l0aW9uID09ICcnIH4gJ05vbmUnLA0KICAgIFRSVUUgfiBTcG9ydC5Qb3NpdGlvbg0KICApKSAlPiUNCiAgZHBseXI6OnNlbGVjdCgtU3BvcnQuUG9zaXRpb24pDQoNCiNtYWtlcyB0aGUgZGF0ZSBjb2x1bW4gYSAnZGF0ZScgb2JqZWN0IGZvciBsYXRlciBhbmQgb21pdHMgTkEgdmFsdWVzIGZvciBub3JkaWMgZGF0YXNldA0KcGVyZm9ybWFuY2VfTF9ub3JkaWMgPC0gcGVyZm9ybWFuY2VfTCAlPiUNCiAgZHBseXI6OnNlbGVjdCgtYygnSGlwLkFiZC5MZWZ0Lk1FQU4nLCAnSGlwLkFiZC5SaWdodC5NRUFOJywgJ0hpcC5BYmR1Y3Rpb24uTUVBTi5JbWJhbGFuY2UnLCAnSGlwLkFiZC5MZWZ0Lk1BWCcsICdIaXAuQWJkLlJpZ2h0Lk1BWCcsICdIaXAuQWJkdWN0aW9uLk1BWC5JbWJhbGFuY2UnLCAnSGlwLkFkZC5MZWZ0Lk1FQU4nLCAnSGlwLkFkZC5SaWdodC5NRUFOJywgJ0hpcC5BZGR1Y3Rpb24uTUVBTi5JbWJhbGFuY2UnLCAnSGlwLkFkZC5MZWZ0Lk1BWCcsICdIaXAuQWRkLlJpZ2h0Lk1BWCcsICdIaXAuQWRkdWN0aW9uLk1BWC5JbWJhbGFuY2UnLCAnQmlsYXRlcmFsLkhpcC5BYmR1Y3Rpb24uQWRkdWN0aW9uLlJhdGlvJykpICU+JQ0KICBmaWx0ZXIoQXRobGV0ZS5Cb2R5d2VpZ2h0Li5rZy4gPiA1KSAlPiUNCiAgbXV0YXRlKERhdGUgPSBhcy5EYXRlKERhdGUsIGZvcm1hdCA9ICclbS8lZC8lWScpLA0KICAgICAgICAgRm9yY2UuRGlmZi5Ob3JtID0gKE1heGltdW0uTm9yZGljLkJpbGF0ZXJhbC5NZWFuIC0gMjc3KSAvIDI3NywNCiAgICAgICAgIEltYmFsYW5jZS5EaWZmLk5vcm0gPSAoTm9yZGljLk1FQU4uSW1iYWxhbmNlIC0gNS44KSAvIDUuOCwNCiAgICAgICAgIFNwb3J0ID0gJ0xhY3Jvc3NlJykgJT4lDQogIG5hLm9taXQoKQ0KDQojbWFrZXMgdGhlIGRhdGUgY29sdW1uIGEgJ2RhdGUnIG9iamVjdCBmb3IgbGF0ZXIgYW5kIG9taXRzIE5BIHZhbHVlcyBmb3IgaGlwIGRhdGFzZXQNCnBlcmZvcm1hbmNlX0xfaGlwIDwtIHBlcmZvcm1hbmNlX0wgJT4lDQogIGRwbHlyOjpzZWxlY3QoLWMoJ05vcmRpYy5MZWZ0Lk1FQU4nLCAnTm9yZGljLlJpZ2h0Lk1FQU4nLCAnTm9yZGljLk1FQU4uSW1iYWxhbmNlJywgJ05vcmRpYy5MZWZ0Lk1BWCcsICdOb3JkaWMuUmlnaHQuTUFYJywgJ05vcmRpYy5NQVguSW1iYWxhbmNlJywgJ1RyZW5kJywgJ05vcmRpYy4uLkRpZmZlcmVuY2UuZnJvbS5GaXJzdC5UZXN0JywgJ01heGltdW0uTm9yZGljLkJpbGF0ZXJhbC5NZWFuJywgJ1JlbGF0aXZlLk1heGltdW0uTm9yZGljLkJpbGF0ZXJhbC5NZWFuJykpICU+JQ0KICBmaWx0ZXIoQXRobGV0ZS5Cb2R5d2VpZ2h0Li5rZy4gPiA1KSAlPiUNCiAgbXV0YXRlKERhdGUgPSBhcy5EYXRlKERhdGUsIGZvcm1hdCA9ICclbS8lZC8lWScpLA0KICAgICAgICAgQWJkLkFkZC5SYXRpby5EaWZmLk5vcm0gPSAoQmlsYXRlcmFsLkhpcC5BYmR1Y3Rpb24uQWRkdWN0aW9uLlJhdGlvIC0gMC45OSkgLyAwLjk5LA0KICAgICAgICAgU3BvcnQgPSAnTGFjcm9zc2UnKSAlPiUNCiAgbmEub21pdCgpDQpgYGANCg0KQWxzbyBkb2VzIG5vdCBjb250YWluIGFueSBpbmZvcm1hdGlvbiBhYm91dCBwb3NpdGlvbmFsIG5vcm1zIHNvIHRoZXJlIGFyZSBubyBwZXJjZW50IGRpZmZlcmVuY2VzIGZyb20gbm9ybS4gODU1IG9ic2VydmF0aW9ucyB3aXRoIHotc2NvcmVzLiA5Mjkgb2JzZXJ2YXRpb25zIHdpdGhvdXQgei1zY29yZXMuIDgxMCBvYnNlcnZhdGlvbnMgaWYgYm9keXdlaWdodCBpcyBpbmNsdWRlZC4gIA0KDQpIaXAgZGF0YXNldCBjb250YWlucyAxMDAgb2JzZXJ2YXRpb25zIHdpdGggYm9keXdlaWdodCBpbmNsdWRlZCBhbmQgZXhjbHVkZWQuIA0KDQojUGVyZm9ybWFuY2UgKFZBTEQpIFZvbGxleWJhbGwgRGF0YQ0KYGBge3J9DQojc2VsZWN0cyB2YXJpYWJsZXMgb2YgaW50ZXJlc3QsIG5vcmRpYyBhbmQgaGlwIGRhdGENCnBlcmZvcm1hbmNlX1YgPC0gc3Vic2V0KFBlcmZvcm1hbmNlX1YsIHNlbGVjdCA9IGMoJ2Fub25faWQnLCAnRGF0ZScsICdBdGhsZXRlLkJvZHl3ZWlnaHQuLmtnLicsJ1Nwb3J0LlBvc2l0aW9uJywgJ1NpZGUnLCAnUmVwZXRpdGlvbnMnLCAnTWF4aW11bS5Gb3JjZScsICdBdmVyYWdlLkZvcmNlJywgJ0ltcHVsc2UnLCAnTm9yZGljLkxlZnQuTUVBTicsICdOb3JkaWMuUmlnaHQuTUVBTicsICdOb3JkaWMuTUVBTi5JbWJhbGFuY2UnLCAnTm9yZGljLkxlZnQuTUFYJywgJ05vcmRpYy5SaWdodC5NQVgnLCAnTm9yZGljLk1BWC5JbWJhbGFuY2UnLCAnVHJlbmQnLCAnTm9yZGljLi4uRGlmZmVyZW5jZS5mcm9tLkZpcnN0LlRlc3QnLCAnTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4nLCAnUmVsYXRpdmUuTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4nLCAnSGlwLkFiZC5MZWZ0Lk1FQU4nLCAnSGlwLkFiZC5SaWdodC5NRUFOJywgJ0hpcC5BYmR1Y3Rpb24uTUVBTi5JbWJhbGFuY2UnLCAnSGlwLkFiZC5MZWZ0Lk1BWCcsICdIaXAuQWJkLlJpZ2h0Lk1BWCcsICdIaXAuQWJkdWN0aW9uLk1BWC5JbWJhbGFuY2UnLCAnSGlwLkFkZC5MZWZ0Lk1FQU4nLCAnSGlwLkFkZC5SaWdodC5NRUFOJywgJ0hpcC5BZGR1Y3Rpb24uTUVBTi5JbWJhbGFuY2UnLCAnSGlwLkFkZC5MZWZ0Lk1BWCcsICdIaXAuQWRkLlJpZ2h0Lk1BWCcsICdIaXAuQWRkdWN0aW9uLk1BWC5JbWJhbGFuY2UnLCAnQmlsYXRlcmFsLkhpcC5BYmR1Y3Rpb24uQWRkdWN0aW9uLlJhdGlvJykpICU+JQ0KICBtdXRhdGUoUG9zaXRpb24gPSBjYXNlX3doZW4oDQogICAgU3BvcnQuUG9zaXRpb24gPT0gJycgfiAnTm9uZScsDQogICAgVFJVRSB+IFNwb3J0LlBvc2l0aW9uDQogICkpICU+JQ0KICBkcGx5cjo6c2VsZWN0KC1TcG9ydC5Qb3NpdGlvbikNCg0KI21ha2VzIHRoZSBkYXRlIGNvbHVtbiBhICdkYXRlJyBvYmplY3QgZm9yIGxhdGVyIGFuZCBvbWl0cyBOQSB2YWx1ZXMgZm9yIG5vcmRpYyBkYXRhc2V0DQpwZXJmb3JtYW5jZV9WX25vcmRpYyA8LSBwZXJmb3JtYW5jZV9WICU+JQ0KICBkcGx5cjo6c2VsZWN0KC1jKCdIaXAuQWJkLkxlZnQuTUVBTicsICdIaXAuQWJkLlJpZ2h0Lk1FQU4nLCAnSGlwLkFiZHVjdGlvbi5NRUFOLkltYmFsYW5jZScsICdIaXAuQWJkLkxlZnQuTUFYJywgJ0hpcC5BYmQuUmlnaHQuTUFYJywgJ0hpcC5BYmR1Y3Rpb24uTUFYLkltYmFsYW5jZScsICdIaXAuQWRkLkxlZnQuTUVBTicsICdIaXAuQWRkLlJpZ2h0Lk1FQU4nLCAnSGlwLkFkZHVjdGlvbi5NRUFOLkltYmFsYW5jZScsICdIaXAuQWRkLkxlZnQuTUFYJywgJ0hpcC5BZGQuUmlnaHQuTUFYJywgJ0hpcC5BZGR1Y3Rpb24uTUFYLkltYmFsYW5jZScsICdCaWxhdGVyYWwuSGlwLkFiZHVjdGlvbi5BZGR1Y3Rpb24uUmF0aW8nKSkgJT4lDQogIGZpbHRlcihBdGhsZXRlLkJvZHl3ZWlnaHQuLmtnLiA+IDUpICU+JQ0KICBtdXRhdGUoRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0ID0gJyVtLyVkLyVZJyksDQogICAgICAgICBGb3JjZS5EaWZmLk5vcm0gPSAoTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4gLSAyODcpIC8gMjg3LA0KICAgICAgICAgSW1iYWxhbmNlLkRpZmYuTm9ybSA9IChOb3JkaWMuTUVBTi5JbWJhbGFuY2UgLSA2LjIpIC8gNi4yLA0KICAgICAgICAgU3BvcnQgPSAnVm9sbGV5YmFsbCcpICU+JQ0KICBuYS5vbWl0KCkNCg0KI21ha2VzIHRoZSBkYXRlIGNvbHVtbiBhICdkYXRlJyBvYmplY3QgZm9yIGxhdGVyIGFuZCBvbWl0cyBOQSB2YWx1ZXMgZm9yIGhpcCBkYXRhc2V0DQpwZXJmb3JtYW5jZV9WX2hpcCA8LSBwZXJmb3JtYW5jZV9WICU+JQ0KICBkcGx5cjo6c2VsZWN0KC1jKCdOb3JkaWMuTGVmdC5NRUFOJywgJ05vcmRpYy5SaWdodC5NRUFOJywgJ05vcmRpYy5NRUFOLkltYmFsYW5jZScsICdOb3JkaWMuTGVmdC5NQVgnLCAnTm9yZGljLlJpZ2h0Lk1BWCcsICdOb3JkaWMuTUFYLkltYmFsYW5jZScsICdUcmVuZCcsICdOb3JkaWMuLi5EaWZmZXJlbmNlLmZyb20uRmlyc3QuVGVzdCcsICdNYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbicsICdSZWxhdGl2ZS5NYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbicpKSAlPiUNCiAgZmlsdGVyKEF0aGxldGUuQm9keXdlaWdodC4ua2cuID4gNSkgJT4lDQogIG11dGF0ZShEYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAnJW0vJWQvJVknKSwNCiAgICAgICAgIEFiZC5BZGQuUmF0aW8uRGlmZi5Ob3JtID0gKEJpbGF0ZXJhbC5IaXAuQWJkdWN0aW9uLkFkZHVjdGlvbi5SYXRpbyAtIDEuMDQpIC8gMS4wNCwNCiAgICAgICAgIFNwb3J0ID0gJ1ZvbGxleWJhbGwnKSAlPiUNCiAgbmEub21pdCgpDQpgYGANCg0KVGhlcmUgYXJlIGEgbG90IG9mIG9ic2VydmF0aW9ucyB3aXRoIHRoZSBwbGF5ZXIgcGxheWluZyBtdWx0aXBsZSBwb3NpdGlvbnMsIG5lZWQgdG8gZmlndXJlIG91dCBob3cgdG8gZmlsdGVyIGRvd24gd2hlbiBhbmFseXppbmcgZGF0YSBieSBwb3NpdGlvbnMuIA0KDQpEb2VzIGhhdmUgcG9zaXRpb25hbCBub3JtIGluZm9ybWF0aW9uIGJ1dCBhIGxvdCBvZiBtaXNzaW5nIHZhbHVlcy4gT25seSAzMyBvYnNlcnZhdGlvbnMgd2l0aCBwZXJjZW50IGRpZmZlcmVuY2Ugbm9ybSBhbmQgei1zY29yZXMuIDM1NiBvYnNlcnZhdGlvbnMgd2l0aCBvbmx5IHotc2NvcmVzLiAzOTMgb2JzZXJ2YXRpb25zIHdpdGhvdXQgZWl0aGVyIHBlcmNlbnQgZGlmZmVyZW5jZSBub3JtIG9yIHotc2NvcmVzLiAzMjUgb2JzZXJ2YXRpb25zIGlmIGJvZHl3ZWlnaHQgaXMgaW5jbHVkZWQuDQoNCkhpcCBkYXRhIGNvbnRhaW5zIDE4MCBvYnNlcnZhdGlvbnMgd2l0aCBib2R5d2VpZ2h0IGluY2x1ZGVkLCAyMjAgb3RoZXJ3aXNlLg0KDQoNCiMjIyBFeHBsb3JhdG9yeSBQbG90cw0KMS4gSW5jaWRlbnQgZGF0YXNldHMNCmBgYHtyfQ0KI2RlbnNpdHkgcGxvdCBvZiBpbmp1cmllcyBhY3Jvc3MgdGhlIGRpZmZlcmVudCBwYXJ0cyBvZiBhIHNlYXNvbiAgDQpnZ3Bsb3QoaW5jaWRlbnRfYiwgYWVzKHg9U2Vhc29uLikpKw0KICBnZW9tX2JhcihmaWxsPSIjQ0ZCODdDIikrDQogIGxhYnModGl0bGU9IlNlYXNvbmFsIEluanVyeSBTcHJlYWQiLHg9IlNlYXNvbiIseT0iRnJlcXVlbmN5IikNCg0KZ2dwbG90KGluY2lkZW50X2IsIGFlcyh4PUdlbmVyYWwubWVjaGFuaXNtKSkrDQogIGdlb21fYmFyKGZpbGw9IiNDRkI4N0MiKSsNCiAgbGFicyh0aXRsZT0iU2Vhc29uYWwgSW5qdXJ5IFNwcmVhZCBieSBNZWNoYW5pc20iLHg9Ik1lY2hhbmlzbSIseT0iRnJlcXVlbmN5IikNCg0KZ2dwbG90KGluY2lkZW50X2IsIGFlcyh4PVBvc2l0aW9uKSkrDQogIGdlb21fYmFyKGZpbGw9IiNDRkI4N0MiKSsNCiAgbGFicyh0aXRsZT0iUG9zaXRpb25hbCBJbmp1cnkgU3ByZWFkIix4PSJQbGF5ZXJzIFBvc2l0aW9ucyIseT0iRnJlcXVlbmN5IikNCmBgYA0KQ29udGFjdCBpbmp1cmllcyBzZWVtIHRvIGJlIHRoZSBiaWdnZXN0IGNvbmNlcm4gZm9yIHdvbWVucyBiYXNrZXRiYWxsIGFyZSBmb2N1cyBvZiBsb3dlciBib2R5IGluanVyaWVzIGlzIHR5cGljYWxseSBub24tY29udGFjdC4gSW4tc2Vhc29uIGlzIHRoZSBiaWdnZXN0IHRpbWUgZm9yIGluanVyaWVzIGluIGJhc2tldGJhbGwuDQoNCmBgYHtyfQ0KI2RlbnNpdHkgcGxvdCBvZiBpbmp1cmllcyBhY3Jvc3MgdGhlIGRpZmZlcmVudCBwYXJ0cyBvZiBhIHNlYXNvbiAgDQpnZ3Bsb3QoaW5jaWRlbnRfcywgYWVzKHg9U2Vhc29uLikpKw0KICBnZW9tX2JhcihmaWxsPSIjQ0ZCODdDIikrDQogIGxhYnModGl0bGU9IlNlYXNvbmFsIEluanVyeSBTcHJlYWQiLHg9IlNlYXNvbiIseT0iRnJlcXVlbmN5IikNCg0KZ2dwbG90KGluY2lkZW50X3MsIGFlcyh4PUdlbmVyYWwubWVjaGFuaXNtKSkrDQogIGdlb21fYmFyKGZpbGw9IiNDRkI4N0MiKSsNCiAgbGFicyh0aXRsZT0iU2Vhc29uYWwgSW5qdXJ5IFNwcmVhZCBieSBNZWNoYW5pc20iLHg9Ik1lY2hhbmlzbSIseT0iRnJlcXVlbmN5IikNCg0KZ2dwbG90KGluY2lkZW50X3MsIGFlcyh4PVBvc2l0aW9uKSkrDQogIGdlb21fYmFyKGZpbGw9IiNDRkI4N0MiKSsNCiAgbGFicyh0aXRsZT0iUG9zaXRpb25hbCBJbmp1cnkgU3ByZWFkIix4PSJQbGF5ZXJzIFBvc2l0aW9ucyIseT0iRnJlcXVlbmN5IikNCmBgYA0KSGlnaGVzdCBmcmVxdWVuY3kgb2YgbG93ZXIgYm9keSBpbmp1cmllcyBpbi1zZWFzb24gYnV0IGFuIHVuZXhwZWN0ZWRseSBoaWdoIHJhdGUgb2YgbG93ZXIgYm9keSBpbmp1cmllcyBpbiB0aGUgb2ZmIHNlYXNvbiBhcyB3ZWxsLiBDb250YWN0IGluanVyaWVzIGFyZSAyeCBhcyBsaWtlbHkgYXMgYSBub24tY29udGFjdCBpbmp1cnkuIA0KDQpgYGB7cn0NCiNkZW5zaXR5IHBsb3Qgb2YgaW5qdXJpZXMgYWNyb3NzIHRoZSBkaWZmZXJlbnQgcGFydHMgb2YgYSBzZWFzb24gIA0KZ2dwbG90KGluY2lkZW50X3YsIGFlcyh4PVNlYXNvbi4pKSsNCiAgZ2VvbV9iYXIoZmlsbD0iI0NGQjg3QyIpKw0KICBsYWJzKHRpdGxlPSJTZWFzb25hbCBJbmp1cnkgU3ByZWFkIix4PSJTZWFzb24iLHk9IkZyZXF1ZW5jeSIpDQoNCmdncGxvdChpbmNpZGVudF92LCBhZXMoeD1HZW5lcmFsLm1lY2hhbmlzbSkpKw0KICBnZW9tX2JhcihmaWxsPSIjQ0ZCODdDIikrDQogIGxhYnModGl0bGU9IlNlYXNvbmFsIEluanVyeSBTcHJlYWQgYnkgTWVjaGFuaXNtIix4PSJJbmp1cnkgTWVjaGFuaXNtIix5PSJGcmVxdWVuY3kiKQ0KDQpnZ3Bsb3QoaW5jaWRlbnRfdiwgYWVzKHg9UG9zaXRpb24pKSsNCiAgZ2VvbV9iYXIoZmlsbD0iI0NGQjg3QyIpKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsaGp1c3Q9MSkpKw0KICBsYWJzKHRpdGxlPSJQb3NpdGlvbmFsIEluanVyeSBTcHJlYWQiLHg9IlBsYXllcnMgUG9zaXRpb25zIix5PSJGcmVxdWVuY3kiKQ0KYGBgDQpUaGlzIGlzIHRoZSBmaXJzdCBzcG9ydCB0aGF0IHdlIHNlZSB0aGUgaGlnaGVzdCBsb3dlciBib2R5IGluanVyeSBmcmVxdWVuY3kgYXMgbm9uLWNvbnRhY3QgaW5qdXJ5IG1lY2hhbmlzbSwgaGlnaGVyIHByb2JhYmlsaXR5IG9mIGdyZWF0ZXIgbG93ZXIgYm9keSBpbmp1cmllcyBpbiB2b2xsZXliYWxsIHRoZW4gYmFza2V0YmFsbCBhbmQgc29jY2VyLg0KDQpgYGB7cn0NCiNkZW5zaXR5IHBsb3Qgb2YgaW5qdXJpZXMgYWNyb3NzIHRoZSBkaWZmZXJlbnQgcGFydHMgb2YgYSBzZWFzb24gIA0KZ2dwbG90KGluY2lkZW50X2wsIGFlcyh4PVNlYXNvbi4pKSsNCiAgZ2VvbV9iYXIoZmlsbD0iI0NGQjg3QyIpKw0KICBsYWJzKHRpdGxlPSJTZWFzb25hbCBJbmp1cnkgU3ByZWFkIix4PSJTZWFzb24iLHk9IkZyZXF1ZW5jeSIpDQoNCmdncGxvdChpbmNpZGVudF9sLCBhZXMoeD1HZW5lcmFsLm1lY2hhbmlzbSkpKw0KICBnZW9tX2JhcihmaWxsPSIjQ0ZCODdDIikrDQogIGxhYnModGl0bGU9IlNlYXNvbmFsIEluanVyeSBTcHJlYWQgYnkgTWVjaGFuaXNtIix4PSJNZWNoYW5pc20iLHk9IkZyZXF1ZW5jeSIpDQoNCmdncGxvdChpbmNpZGVudF9sLCBhZXMoeD1Qb3NpdGlvbikpKw0KICBnZW9tX2JhcihmaWxsPSIjQ0ZCODdDIikrDQogIGxhYnModGl0bGU9IlBvc2l0aW9uYWwgSW5qdXJ5IFNwcmVhZCIseD0iUGxheWVycyBQb3NpdGlvbnMiLHk9IkZyZXF1ZW5jeSIpDQpgYGANCkxpa2Ugdm9sbGV5YmFsbCBzdHJvbmcgbGVhZCBvZiBub24tY29udGFjdCBpbmp1cmllcyB0aGVuIGFueSBvdGhlciB0eXBlIG9mIGluanVyeSBtZWNoYW5pc20uDQoNCjIuIER5bmFtbyBkYXRhc2V0cw0KYGBge3J9DQojYWRkaW5nIGEgY29sdW1uIHRvIGVhY2ggZGF0YXNldCBkZXNjcmliaW5nIHRoZSBzcG9ydCBmb3IgZXhwbG9yYXRvcnkgcHVycG9zZXMNCmR5bmFtb19CJFNwb3J0IDwtICdCYXNrZXRiYWxsJw0KZHluYW1vX1MkU3BvcnQgPC0gJ1NvY2NlcicNCmR5bmFtb19MJFNwb3J0IDwtICdMYWNyb3NzZScNCmR5bmFtb19WJFNwb3J0IDwtICdWb2xsZXliYWxsJw0KDQojY3JlYXRpbmcgYSBkYXRhc2V0IGNvbnRhaW5pbmcgZHluYW1vIGRhdGEgYWNjcm9zcyBhbGwgc3BvcnRzDQpkeW5hbW9fYWxsIDwtIHJiaW5kKGR5bmFtb19CLCBkeW5hbW9fUywgZHluYW1vX0wsIGR5bmFtb19WKSAlPiUNCiAgbXV0YXRlKEF2Zy5NYXguRm9yY2UgPSAoS25lZS5FeC5SaWdodC5TaWRlLk1heC5Gb3JjZS4uTi4gKyBLbmVlLkV4LkxlZnQuU2lkZS5NYXguRm9yY2UuLk4uKSAvIDIpDQpgYGANCg0KYGBge3J9DQojY3JlYXRlcyBhIGJveHBsb3Qgb2YgYXZlcmFnZSBmb3JjZSBhc3ltbWV0cnkgYWNyb3NzIHRoZSA0IHNwb3J0cw0KZ2dwbG90KGR5bmFtb19hbGwsIGFlcyh4ID0gS25lZS5FeC5BdmcuRm9yY2UuQXN5bW1ldHJ5LCB5ID0gU3BvcnQpKSArDQogIGdlb21fYm94cGxvdChmaWxsID0gJyNDRkI4N0MnLCBjb2xvciA9ICdibGFjaycpICsgDQogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIEF2Z2VyYWdlIEZvcmNlIEFzeW1tZXRyeSBBY3Jvc3MgU3BvcnRzJywNCiAgICAgICB5ID0gJ1Nwb3J0JywNCiAgICAgICB4ID0gJ0F2ZXJhZ2UgRm9yY2UgQXN5bW1ldHJ5JykgKw0KICB0aGVtZV9idygpDQpgYGANCg0KYGBge3J9DQojY3JlYXRlcyBhIGhpc3RvZ3JhbSBvZiBkeW5hbW8gbWF4IGZvcmNlIGFjcm9zcyB0aGUgNCBzcG9ydHMNCmdncGxvdChkeW5hbW9fYWxsLCBhZXMoeCA9IEF2Zy5NYXguRm9yY2UsIGZpbGwgPSBTcG9ydCkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3IgPSAnYmxhY2snLCBwb3NpdGlvbiA9ICdpZGVudGl0eScsIGJpbnMgPSAyMCkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCcjNTY1QTVDJywgJyNDRkI4N0MnLCAnIzAwMDAwMCcsICcjQTJBNEEzJykpICsNCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgQXZlcmFnZSBEeW5hbW8gTWF4IEZvcmNlIEFjcm9zcyBTcG9ydHMnLA0KICAgICAgIHkgPSAnU3BvcnQnLA0KICAgICAgIHggPSAnQXZlcmFnZSBNYXggRm9yY2UgKE4pJykgKw0KICB0aGVtZV9idygpDQpgYGANCg0KVGhpcyBkYXRhIHdpbGwgcHJvYmFibHkgbm90IGJlIHZlcnkgdXNlZnVsIGVzcGVjaWFsbHkgc2luY2Ugb25seSB0d28gdW5pcXVlIHBsYXllcnMgYXJlIHJlcHJlc2VudGVkIGluIFdCQiwgYW5kIG9ubHkgb25lIGluIGJvdGggV1ZCIGFuZCBXU09DIFdMQVggaGFzIDkgdW5pcXVlIHBsYXllcnMgYnV0IHZlcnkgZmV3IGNvbXBhcmlzb25zIGNhbiBiZSBtYWRlIGFjcm9zcyBzcG9ydHMuIA0KDQozLiBGb3JjZWRlY2tzIA0KVmFyaWFibGUgRGlzdHJpYnV0aW9uIFBsb3RzDQpgYGB7cn0NCiNiYXNrZXRiYWxsLCBDTUogdGVzdDogZGlzdHJpYnV0aW9uIG9mIG1heCBSU0kNCmdncGxvdChDTUpfYmIsIGFlcyhNYXguQ01KLlJTSS5Nb2RpZmllZC4ubS5zLikpICsNCiAgbGFicyh0aXRsZT0iRGlzdHJpYnV0aW9uIG9mIE1heGltdW0gUlNJIGluIENNSiBUZXN0Iix4PSJSU0kiLCB5PSJGcmVxdWVuY3kiKSArDQogIGdlb21faGlzdG9ncmFtKGZpbGw9IiNDRkI4N0MiKQ0KDQojSEogVEVTVDogZGlzdHJpYnV0aW9uIG9mIE1lYW4uUlNJLi5GbGlnaHQuQ29udGFjdC5UaW1lIA0KZ2dwbG90KEhKX0IsIGFlcyhNZWFuLlJTSS4uRmxpZ2h0LkNvbnRhY3QuVGltZS4pKSArDQogIGxhYnModGl0bGU9IkRpc3RyaWJ1dGlvbiBvZiBSU0kgRmxpZ2h0IENvbnRhY3QgVGltZSBpbiB0aGUgSG9wIEp1bXAgVGVzdCIseD0iQXZlcmFnZSBSU0kgRmxpZ2h0IENvbnRhY3QgVGltZSIsIHk9IkZyZXF1ZW5jeSIpICsNCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbD0iI0NGQjg3QyIpDQoNCiNJTVRQIHRlc3Q6IGRpc3RyaWJ1dGlvbiBvZiBwZWFrIHZlcnQuIGZvcmNlDQpnZ3Bsb3QoSU1UUF9CLCBhZXMoTmV0LlBlYWsuVmVydGljYWwuRm9yY2UuLk4ucy4pKSArDQogIGxhYnModGl0bGU9IkRpc3RyaWJ1dGlvbiBvZiBJTVRQIFRlc3QiLHg9IlBlYWsgVmVydGljYWwgRm9yY2UiLCB5PSJGcmVxdWVuY3kiKSArDQogIGdlb21faGlzdG9ncmFtKGZpbGw9IiNDRkI4N0MiKQ0KYGBgDQoNCmBgYHtyfQ0KI1NPQ0NFUiwgQ01KIHRlc3Q6IGRpc3RyaWJ1dGlvbiBvZiBtYXggUlNJIA0KZ2dwbG90KENNSl9zb2MsIGFlcyhNYXguQ01KLlJTSS5Nb2RpZmllZC4ubS5zLikpICsNCiAgbGFicyh0aXRsZT0iRGlzdHJpYnV0aW9uIG9mIE1heGltdW0gUlNJIGluIENNSiBUZXN0Iix4PSJSU0kiLCB5PSJGcmVxdWVuY3kiKSArDQogIGdlb21faGlzdG9ncmFtKGZpbGw9IiNDRkI4N0MiKQ0KDQojSEogVEVTVDogZGlzdHJpYnV0aW9uIG9mIE1lYW4uUlNJLi5GbGlnaHQuQ29udGFjdC5UaW1lIA0KZ2dwbG90KEhKX1MsIGFlcyhNZWFuLlJTSS4uRmxpZ2h0LkNvbnRhY3QuVGltZS4pKSArDQogIGxhYnModGl0bGU9IkRpc3RyaWJ1dGlvbiBvZiBSU0kgRmxpZ2h0IENvbnRhY3QgVGltZSBpbiB0aGUgSG9wIEp1bXAgVGVzdCIseD0iQXZlcmFnZSBSU0kgRmxpZ2h0IENvbnRhY3QgVGltZSIsIHk9IkZyZXF1ZW5jeSIpICsNCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbD0iI0NGQjg3QyIpDQoNCiNJTVRQIHRlc3Q6IGRpc3RyaWJ1dGlvbiBvZiBwZWFrIHZlcnQuIGZvcmNlDQpnZ3Bsb3QoSU1UUF9TLCBhZXMoTmV0LlBlYWsuVmVydGljYWwuRm9yY2UuLk4ucy4pKSArDQogIGxhYnModGl0bGU9IkRpc3RyaWJ1dGlvbiBvZiBJTVRQIFRlc3QiLHg9IlBlYWsgVmVydGljYWwgRm9yY2UiLCB5PSJGcmVxdWVuY3kiKSArDQogIGdlb21faGlzdG9ncmFtKGZpbGw9IiNDRkI4N0MiKQ0KDQojU0xKIHRlc3Q6IGRpc3RyaWJ1dGlvbiAgDQpnZ3Bsb3QoU0xKX1MsIGFlcyhDb25jZW50cmljLkltcHVsc2UuLk5zLikpICsNCiAgbGFicyh0aXRsZT0iRGlzdHJpYnV0aW9uIG9mIENvbmNlbnRyaWMgSW1wdWxzZSBpbiBTTEogVGVzdCIseD0iQ29uY2VudHJpYyBJbXB1bHNlIiwgeT0iRnJlcXVlbmN5IikgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsPSIjQ0ZCODdDIikNCmBgYA0KDQpgYGB7cn0NCiNMQUNST1NTRSwgQ01KIHRlc3Q6IGRpc3RyaWJ1dGlvbiBvZiBtYXggUlNJIA0KZ2dwbG90KENNSl9sYXgsIGFlcyhNYXguQ01KLlJTSS5Nb2RpZmllZC4ubS5zLikpICsNCiAgbGFicyh0aXRsZT0iRGlzdHJpYnV0aW9uIG9mIE1heGltdW0gUlNJIGluIENNSiBUZXN0Iix4PSJSU0kiLCB5PSJGcmVxdWVuY3kiKSArDQogIGdlb21faGlzdG9ncmFtKGZpbGw9IiNDRkI4N0MiKQ0KDQojSEogVEVTVDogZGlzdHJpYnV0aW9uIG9mIE1lYW4uUlNJLi5GbGlnaHQuQ29udGFjdC5UaW1lIA0KZ2dwbG90KEhKX0wsIGFlcyhNZWFuLlJTSS4uRmxpZ2h0LkNvbnRhY3QuVGltZS4pKSArDQogIGxhYnModGl0bGU9IkRpc3RyaWJ1dGlvbiBvZiBSU0kgRmxpZ2h0IENvbnRhY3QgVGltZSBpbiB0aGUgSG9wIEp1bXAgVGVzdCIseD0iQXZlcmFnZSBSU0kgRmxpZ2h0IENvbnRhY3QgVGltZSIsIHk9IkZyZXF1ZW5jeSIpICsNCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbD0iI0NGQjg3QyIpDQoNCiNJTVRQIHRlc3Q6IGRpc3RyaWJ1dGlvbiBvZiBwZWFrIHZlcnQuIGZvcmNlDQpnZ3Bsb3QoSU1UUF9MLCBhZXMoTmV0LlBlYWsuVmVydGljYWwuRm9yY2UuLk4ucy4pKSArDQogIGxhYnModGl0bGU9IkRpc3RyaWJ1dGlvbiBvZiBJTVRQIFRlc3QiLHg9IlBlYWsgVmVydGljYWwgRm9yY2UiLCB5PSJGcmVxdWVuY3kiKSArDQogIGdlb21faGlzdG9ncmFtKGZpbGw9IiNDRkI4N0MiKQ0KDQojU0xKIHRlc3Q6IGRpc3RyaWJ1dGlvbiAgDQpnZ3Bsb3QoU0xKX0wsIGFlcyhDb25jZW50cmljLkltcHVsc2UuLk5zLikpICsNCiAgbGFicyh0aXRsZT0iRGlzdHJpYnV0aW9uIG9mIENvbmNlbnRyaWMgSW1wdWxzZSBpbiBTTEogVGVzdCIseD0iQ29uY2VudHJpYyBJbXB1bHNlIiwgeT0iRnJlcXVlbmN5IikgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsPSIjQ0ZCODdDIikNCmBgYA0KDQpgYGB7cn0NCiNWT0xMRVlCQUxMLCBDTUogdGVzdDogZGlzdHJpYnV0aW9uIG9mIG1heCBSU0kgDQpnZ3Bsb3QoQ01KX3ZiLCBhZXMoTWF4LkNNSi5SU0kuTW9kaWZpZWQuLm0ucy4pKSArDQogIGxhYnModGl0bGU9IkRpc3RyaWJ1dGlvbiBvZiBNYXhpbXVtIFJTSSBpbiBDTUogVGVzdCIseD0iUlNJIiwgeT0iRnJlcXVlbmN5IikgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsPSIjQ0ZCODdDIikNCg0KI0hKIFRFU1Q6IGRpc3RyaWJ1dGlvbiBvZiBNZWFuLlJTSS4uRmxpZ2h0LkNvbnRhY3QuVGltZSANCmdncGxvdChISl9WLCBhZXMoTWVhbi5SU0kuLkZsaWdodC5Db250YWN0LlRpbWUuKSkgKw0KICBsYWJzKHRpdGxlPSJEaXN0cmlidXRpb24gb2YgUlNJIEZsaWdodCBDb250YWN0IFRpbWUgaW4gdGhlIEhvcCBKdW1wIFRlc3QiLHg9IkF2ZXJhZ2UgUlNJIEZsaWdodCBDb250YWN0IFRpbWUiLCB5PSJGcmVxdWVuY3kiKSArDQogIGdlb21faGlzdG9ncmFtKGZpbGw9IiNDRkI4N0MiKQ0KDQojSU1UUCB0ZXN0OiBkaXN0cmlidXRpb24gb2YgcGVhayB2ZXJ0LiBmb3JjZQ0KZ2dwbG90KElNVFBfViwgYWVzKE5ldC5QZWFrLlZlcnRpY2FsLkZvcmNlLi5OLnMuKSkgKw0KICBsYWJzKHRpdGxlPSJEaXN0cmlidXRpb24gb2YgSU1UUCBUZXN0Iix4PSJQZWFrIFZlcnRpY2FsIEZvcmNlIiwgeT0iRnJlcXVlbmN5IikgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsPSIjQ0ZCODdDIikNCmBgYA0KDQo0LiBQZXJmb3JtYW5jZQ0KYGBge3J9DQojQkFTS0VUQkFMTA0KI3N1bW1hcml6ZXMgdGhlIG51bWJlciBvZiB1bmlxdWUgYXRobGV0ZXMgcGVyIHBvc2l0aW9uIGdyb3VwDQpwZXJmb3JtYW5jZV9CX25vcmRpYyAlPiUNCiAgZ3JvdXBfYnkoUG9zaXRpb24pICU+JQ0KICBzdW1tYXJpemUoYFVuaXF1ZSBBdGhsZXRlc2AgPSBuX2Rpc3RpbmN0KGFub25faWQpKQ0KYGBgDQpUaGVyZSBhcmUgb25seSA0IHVuaXF1ZSBjZW50ZXJzIHJlcHJlc2VudGVkIHdpdGggbW9zdCBvZiB0aGUgb2JzZXJ2YXRpb25zIGJlaW5nIElEXzQwIGFuZCBJRF81MSwgSURfMTUgYW5kIElEXzMwIGVhY2ggb25seSBoYXZlIG9uZSBvYnNlcnZhdGlvbi4gRm9yd2FyZHMgb25seSBoYXZlIDggdW5pcXVlIHBsYXllcnMgYnV0IHRoZSBzcGxpdCBiZXR3ZWVuIHRoZXNlIHBsYXllcnMgaXMgbW9yZSBldmVuIHdpdGggdGhlIGV4Y2VwdGlvbiBvZiBJRF8yNCB3aG8gb25seSBoYXMgb25lIG9ic2VydmF0aW9uLiBHdWFyZHMgaGFzIDEwIHVuaXF1ZSBwbGF5ZXJzIHdpdGggSURfNTUgbWFraW5nIHVwIGEgbGFyZ2UgcHJvcG9ydGlvbiBvZiB0aGVzZSBvYnNlcnZhdGlvbnMgYW5kIElEXzUsIElEXzU0LCBhbmQgSURfNjMgb25seSBiZWluZyByZXByZXNlbnRlZCBvbmNlLiANCg0KYGBge3J9DQojY3JlYXRlcyBhIGJveHBsb3Qgb2YgbWF4aW11bSByZWxhdGl2ZSBiaWxhdGVyYWwgZm9yY2UgYWNyb3NzIHRoZSBiYXNrZXRiYWxsIHBvc2l0aW9ucw0KZ2dwbG90KHBlcmZvcm1hbmNlX0Jfbm9yZGljLCBhZXMoeCA9IFJlbGF0aXZlLk1heGltdW0uTm9yZGljLkJpbGF0ZXJhbC5NZWFuLCB5ID0gUG9zaXRpb24pKSArDQogIGdlb21fYm94cGxvdChmaWxsID0gJyNDRkI4N0MnLCBjb2xvciA9ICdibGFjaycpICsgDQogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIE1heGltdW0gUmVsYXRpdmUgQmlsYXRlcmFsIEZvcmNlIEFjcm9zcyBCYXNrZXRiYWxsIFBvc3Rpb25zJywNCiAgICAgICB5ID0gJ1Bvc2l0aW9uJywNCiAgICAgICB4ID0gJ01heGltdW0gUmVsYXRpdmUgQmlsYXRlcmFsIEZvcmNlIChOIC8ga2cpJykgKw0KICB0aGVtZV9idygpDQpgYGANCkNlbnRlcnMgYXBwZWFyIHRvIGhhdmUgYSBmYXIgZ3JlYXRlciB2YXJpYWJpbGl0eSBpbiBmb3JjZSBhbG9uZyB3aXRoIGEgbG93ZXIgbWVkaWFuIG9mIGZvcmNlIGluIGNvbXBhcmlzb24gdG8gZm9yd2FyZHMgYW5kIGd1YXJkcy4gVGhlIHNhbWUgYXBwZWFycyB0byBiZSB0cnVlIGZvciB0aGUgcmVsYXRpdmUgZm9yY2UuIEludGVyZXN0aW5nbHkgd2hlbiBwbG90dGluZyB0aGUgYXRobGV0ZSBib2R5d2VpZ2h0IHZzIHBvc2l0aW9uIHRoZXJlIGlzIG5vIHNpZ25pZmlhbnQgZGlmZmVyZW5jZXMgYW5kIHRoZSBtZWRpYW4gd2VpZ2h0IGZvciBjZW50ZXJzIGlzIGxlc3MgdGhhbiB0aGUgbWVkaWFuIHdlaWdodCBvZiBndWFyZHMgYW5kIGZvcndhcmRzLiANCg0KYGBge3J9DQojU09DQ0VSDQojc3VtbWFyaXplcyB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBhdGhsZXRlcyBwZXIgcG9zaXRpb24gZ3JvdXANCnBlcmZvcm1hbmNlX1Nfbm9yZGljICU+JQ0KICBncm91cF9ieShQb3NpdGlvbikgJT4lDQogIHN1bW1hcml6ZShgVW5pcXVlIEF0aGxldGVzYCA9IG5fZGlzdGluY3QoYW5vbl9pZCkpDQpgYGANClRoZXJlIGFyZSBvbmx5IG9uZSB1bmlxdWUgb3V0c2lkZSBiYWNrIGFuZCBjZW50ZXIgYmFjayBwbGF5ZXJzLiBPbmx5IDQgZGVmZW5zZSBtaWRmaWVsZCBwbGF5ZXJzIHdpdGggSURfMzIgb25seSBoYXZpbmcgb25lIG9ic2VydmF0aW9uLiBPbmx5IDMgZ29hbGllcywgcmVsYXRpdmVseSBldmVuIGRpc3RyaWJ1dGlvbiBvZiBvYnNlcnZhdGlvbnMuIDcgZm9yd2FyZHMsIGFsc28gcHJldHR5IGV2ZW4gZGlzdHJpYnV0aW9uIG9mIG9ic2VydmF0aW9ucy4gNyBtaWRmZWlsZGVycyB3aXRoIElEXzk0IGFuZCBJRF8zMiBvbmx5IHJlcHJlc2VudGluZyBvbmUgb2JzZXJ2YXRpb24gZWFjaC4gDQoNCmBgYHtyfQ0KI2NyZWF0ZXMgYSBib3hwbG90IG9mIG1heGltdW0gcmVsYXRpdmUgYmlsYXRlcmFsIGZvcmNlIGFjcm9zcyB0aGUgYmFza2V0YmFsbCBwb3NpdGlvbnMNCmdncGxvdChwZXJmb3JtYW5jZV9TX25vcmRpYywgYWVzKHggPSBSZWxhdGl2ZS5NYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbiwgeSA9IFBvc2l0aW9uKSkgKw0KICBnZW9tX2JveHBsb3QoZmlsbCA9ICcjQ0ZCODdDJywgY29sb3IgPSAnYmxhY2snKSArIA0KICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBNYXhpbXVtIFJlbGF0aXZlIEJpbGF0ZXJhbCBGb3JjZSBBY3Jvc3MgQmFza2V0YmFsbCBQb3N0aW9ucycsDQogICAgICAgeSA9ICdQb3NpdGlvbicsDQogICAgICAgeCA9ICdNYXhpbXVtIFJlbGF0aXZlIEJpbGF0ZXJhbCBGb3JjZSAoTiAvIGtnKScpICsNCiAgdGhlbWVfYncoKQ0KYGBgDQpUaGVyZSBpcyBhIGJpZyBvdXRsaWVyIGluIElEXzMgd2hvcyBtZWFuIG1heGltdW0gYmlsYXRlcmFsIGZvcmNlIGluIG5ld3RvbnMgd2FzIGxlc3MgdGhhbiBoZXIgYm9keXdlaWdodCBpbiBrZy4NCg0KYGBge3J9DQojTEFDUk9TU0UNCiNzdW1tYXJpemVzIHRoZSBudW1iZXIgb2YgdW5pcXVlIGF0aGxldGVzIHBlciBwb3NpdGlvbiBncm91cA0KcGVyZm9ybWFuY2VfTF9ub3JkaWMgJT4lDQogIGdyb3VwX2J5KFBvc2l0aW9uKSAlPiUNCiAgc3VtbWFyaXplKGBVbmlxdWUgQXRobGV0ZXNgID0gbl9kaXN0aW5jdChhbm9uX2lkKSkNCmBgYA0KVGhpcyBkYXRhc2V0IHNlZW1zIHRvIGhhdmUgYSBiZXR0ZXIgYW1vdW50IG9mIHVuaXF1ZSBwbGF5ZXJzIHBlciBwb3NpdGlvbi4gDQoNCmBgYHtyfQ0KI2NyZWF0ZXMgYSBib3hwbG90IG9mIG1heGltdW0gcmVsYXRpdmUgYmlsYXRlcmFsIGZvcmNlIGFjcm9zcyB0aGUgYmFza2V0YmFsbCBwb3NpdGlvbnMNCmdncGxvdChwZXJmb3JtYW5jZV9MX25vcmRpYywgYWVzKHggPSBSZWxhdGl2ZS5NYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbiwgeSA9IFBvc2l0aW9uKSkgKw0KICBnZW9tX2JveHBsb3QoZmlsbCA9ICcjQ0ZCODdDJywgY29sb3IgPSAnYmxhY2snKSArIA0KICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBNYXhpbXVtIFJlbGF0aXZlIEJpbGF0ZXJhbCBGb3JjZSBBY3Jvc3MgQmFza2V0YmFsbCBQb3N0aW9ucycsDQogICAgICAgeSA9ICdQb3NpdGlvbicsDQogICAgICAgeCA9ICdNYXhpbXVtIFJlbGF0aXZlIEJpbGF0ZXJhbCBGb3JjZSAoTiAvIGtnKScpICsNCiAgdGhlbWVfYncoKQ0KYGBgDQpBbGwgdGhlIHBvc2l0aW9ucyBzZWVtIHRvIGhhdmUgYSBzaW1pbGFyIGRpc3RyaWJ1dGlvbiBvZiBtYXhpbXVtIHJlbGF0aXZlIGJpbGF0ZXJhbCBmb3JjZS4NCg0KYGBge3J9DQojVk9MTEVZQkFMTA0KI3N1bW1hcml6ZXMgdGhlIG51bWJlciBvZiB1bmlxdWUgYXRobGV0ZXMgcGVyIHBvc2l0aW9uIGdyb3VwDQpwZXJmb3JtYW5jZV9WX25vcmRpYyAlPiUNCiAgZ3JvdXBfYnkoUG9zaXRpb24pICU+JQ0KICBzdW1tYXJpemUoYFVuaXF1ZSBBdGhsZXRlc2AgPSBuX2Rpc3RpbmN0KGFub25faWQpKQ0KYGBgDQoNClRoZXJlIGFyZSB2ZXJ5IGZldyB1bmlxdWUgYXRobGV0ZXMgcGVyIHBvc2l0aW9uIGluIHRoaXMgZGF0YXNldCwgbmVlZCB0byBmaWd1cmUgb3V0IGhvdyB3ZSBjYW4gYXNzaWduIHR3byBwb3NpdGlvbiBhdGhsZXRlcyBpbnRvIG9uZSBmb3IgYmV0dGVyIGFuYWx5c2lzIG9mIHBvc2l0aW9ucy4gIA0KDQpgYGB7cn0NCiNjcmVhdGVzIGEgYm94cGxvdCBvZiBtYXhpbXVtIHJlbGF0aXZlIGJpbGF0ZXJhbCBmb3JjZSBhY3Jvc3MgdGhlIGJhc2tldGJhbGwgcG9zaXRpb25zDQpnZ3Bsb3QocGVyZm9ybWFuY2VfVl9ub3JkaWMsIGFlcyh4ID0gUmVsYXRpdmUuTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4sIHkgPSBQb3NpdGlvbikpICsNCiAgZ2VvbV9ib3hwbG90KGZpbGwgPSAnI0NGQjg3QycsIGNvbG9yID0gJ2JsYWNrJykgKyANCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgTWF4aW11bSBSZWxhdGl2ZSBCaWxhdGVyYWwgRm9yY2UgQWNyb3NzIEJhc2tldGJhbGwgUG9zdGlvbnMnLA0KICAgICAgIHkgPSAnUG9zaXRpb24nLA0KICAgICAgIHggPSAnTWF4aW11bSBSZWxhdGl2ZSBCaWxhdGVyYWwgRm9yY2UgKE4gLyBrZyknKSArDQogIHRoZW1lX2J3KCkNCmBgYA0KDQojI01FUkdFIERBVEFTRVRTIA0KLWluY2lkZW50ICsgcGVyZm9ybWFuY2UgKG5vcmRpYyArIGhpcCksIGZvcmNlZnJhbWUgKG11bHRpcGxlIHRlc3RzKQ0KLWR5bmFtbyBub3QgdG8gYmUgYWRkZWQgDQpUaGVzZSBhcmUgZ3JvdXBlZCBieSBhbGwgZGF0YSBvZiBlYWNoIHNwb3J0LiBEbyBub3Qga25vdyBpZiB3aWxsIHVzZSBhcyB3ZSB3YW50IHRvIGNvbXBhcmUgbWV0cmljcyBhY3Jvc3Mgc3BvcnRzLiBLZWVwIEp1c3QgaW4gY2FzZS4NCmBgYHtyfQ0KI2Jhc2tldGJhbGwgaW5jaWRlbnRzICsgdGVzdHMgDQpCX2luY2lkX0NNSnRlc3QgPC0gbWVyZ2UoaW5jaWRlbnRfYiwgQ01KX2JiLCBieT1jKCdhbm9uX2lkJyksYWxsPVRSVUUpICMxMzEyIGJ5IDYxIA0KQl9pbmNpZF9ISnRlc3QgPC0gbWVyZ2UoaW5jaWRlbnRfYiwgSEpfQiwgYnk9YygnYW5vbl9pZCcpLGFsbD1UUlVFKSAgICAjMjAyMCBieSA0Ng0KQl9pbmNpZF9JTVRQdGVzdCA8LSBtZXJnZShpbmNpZGVudF9iLCBJTVRQX0IsIGJ5PWMoJ2Fub25faWQnKSxhbGw9VFJVRSkgIzMxNSBieSA1Ng0KDQojc29jY2VyIGluY2lkZW50cyArIHRlc3RzIA0KU19pbmNpZF9DTUp0ZXN0IDwtIG1lcmdlKGluY2lkZW50X3MsIENNSl9zb2MsIGJ5PWMoJ2Fub25faWQnKSxhbGw9VFJVRSkgIzE5MTEgYnkgNjMNClNfaW5jaWRfSEp0ZXN0IDwtIG1lcmdlKGluY2lkZW50X3MsIEhKX1MsIGJ5PWMoJ2Fub25faWQnKSxhbGw9VFJVRSkgICAgIzMyMDAgYnkgNDcNClNfaW5jaWRfSU1UUHRlc3QgPC0gbWVyZ2UoaW5jaWRlbnRfcywgSU1UUF9TLCBieT1jKCdhbm9uX2lkJyksYWxsPVRSVUUpICM1OTYgYnkgNTcNClNfaW5jaWRfU0xKdGVzdCA8LSBtZXJnZShpbmNpZGVudF9zLCBTTEpfUywgYnk9YygnYW5vbl9pZCcpLGFsbD1UUlVFKSAgICMzNzIzIGJ5IDUyDQpgYGANCg0KIyNSRVNFQVJDSCBRVUVTVElPTlMqKioqKioqDQojUTE6IFdoYXQgYXJlIG1lYW5pbmdmdWwgdGhyZXNob2xkcyBmb3Igc3RyZW5ndGggbWV0cmljcyBhcyB0aGV5IHJlbGF0ZSB0byBsb3dlciBib2R5IGluanVyeSByaXNrPyANCmEuIEZvciBleGFtcGxlLCBvbmUgb2Ygb3VyIHN0cmVuZ3RoIGNvYWNoZXMgdXNlcyA1IHRpbWVzIGJvZHkgd2VpZ2h0IChrZykgaW4gTmV3dG9ucyBmb3IgaGFtc3RyaW5nIHN0cmVuZ3RoIGFzIGEgY3V0b2ZmIGZvciBpbmp1cnkgcmlzay4gSXMgdGhpcyBzdXBwb3J0ZWQgYnkgb3VyIGRhdGE/IA0KDQotbG9va2luZyBmb3IgbWVhbmluZ2Z1bCBzdHJlbmd0aCBtZXRyaWNzIHRvIGxvd2VyIGJvZHkgaW5qdXJ5IHJpc2sNCi1jcmVhdGUgdGhyZXNob2xkcyBmb3IgdGhlc2UgbWV0cmljcyBieSBlYWNoIHBvc2l0aW9uIGluIGVhY2ggc3BvcnQNCmBgYHtyfQ0KI21lcmdlIGFsbCBpbmNpZGVudCBkYXRhc2V0cw0KYWxsX2luY2lkZW50IDwtIGJpbmRfcm93cyhpbmNpZGVudF9iLCBpbmNpZGVudF9zLCBpbmNpZGVudF92LGluY2lkZW50X2wpICU+JQ0KICBzZWxlY3QoLWMoSW5jaWRlbnQuVHlwZSxUb3RhbC5UaW1lLkluanVyZWQuMSkpDQoNCiNQRVJGT1JNQU5DRQ0KI2NyZWF0ZSBhIGRhdGFzZXQgY29udGFpbmluZyBhbGwgcGVyZm9ybWFuY2UgaGlwIGRhdGEgYWNyb3NzIGFsbCBzcG9ydHMgICsgY29tYmluZSB3LyBpbmNpZGVudHMNCmFsbF9wZXJmX2hpcCA8LSByYmluZChwZXJmb3JtYW5jZV9CX2hpcCwgcGVyZm9ybWFuY2VfTF9oaXAsIHBlcmZvcm1hbmNlX1NfaGlwLCBwZXJmb3JtYW5jZV9WX2hpcCkNCmFsbF9oaXBfaW5jaWRlbnQgPC0gbWVyZ2UoYWxsX2luY2lkZW50LCBhbGxfcGVyZl9oaXAsYnk9YygnYW5vbl9pZCcpLCBuYS5ybT1UUlVFKSAgIzE1MjggdiA0OQ0KI2NyZWF0ZSBhIGRhdGFzZXQgY29udGFpbmluZyBhbGwgcHJlZm9ybWFuY2Ugbm9yZGljIGRhdGEgYWNyb3NzIGFsbCBzcG9ydHMgICsgY29tYmluZSB3LyBpbmNpZGVudHMNCmFsbF9wZXJmX25vcmRpYyA8LSByYmluZChwZXJmb3JtYW5jZV9CX25vcmRpYywgcGVyZm9ybWFuY2VfTF9ub3JkaWMsIHBlcmZvcm1hbmNlX1Nfbm9yZGljLCBwZXJmb3JtYW5jZV9WX25vcmRpYykNCmBgYA0KDQpgYGB7cn0NCiNHSVZFTiANCiNjb25maXJtIG9yIGRlbnkgdGhyZXNob2xkIG9mIDV4IGJvZHl3ZWlnaHQgKGtnKSBpbiBOIGZvciBoYW1zdHJpbmcgc3RyZW5ndGggZm9yIGluanVyeSByaXNrDQphbGxfcGVyZl9ub3JkaWMgPC0gIGFsbF9wZXJmX25vcmRpYyAlPiUgIA0KICBtdXRhdGUoc3RyZW5ndGhfcmF0aW89TWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4vQXRobGV0ZS5Cb2R5d2VpZ2h0Li5rZy4sIA0KICAgICAgICAgYWJvdmVfdGhyZXNob2xkPWlmZWxzZShzdHJlbmd0aF9yYXRpbz49IDUsIDEsMCkpICAjaGFtc3RyaW5nIHN0cmVuZ3RoL3dlaWdodA0KDQphbGxfbm9yZGljX2luY2lkZW50IDwtIG1lcmdlKGFsbF9pbmNpZGVudCwgYWxsX3BlcmZfbm9yZGljLGJ5PWMoJ2Fub25faWQnKSwgbmEucm09VFJVRSkgIzY0OTEgdiA0OA0KDQojRG9lcyBiZWluZyBhYm92ZSB0aGUgdGhyZXNob2xkIHJlbGF0ZSB0byBsb3dlciBib2R5IGluanVyeSByaXNrPw0KbW9kZWwgPC0gZ2xtKExCLkluanVyeX4gYWJvdmVfdGhyZXNob2xkLGRhdGE9YWxsX25vcmRpY19pbmNpZGVudCwgZmFtaWx5PSJiaW5vbWlhbCIpDQpzdW1tYXJ5KG1vZGVsKQ0KYGBgDQpBYm92ZSB0aHJlc2hvbGQgaGF2aW5nIGEgbmVnYXRpdmUgZXN0aW1hdGUgYW5kIGJlaW5nIHNpZ25pZmljYW50ICwgbWVhbnMgdGhhdCBiZWluZyBhYm92ZSB0aGUgNXggdGhyZXNob2xkIGlzIGFzc29jaWF0ZWQgd2l0aCBhIHJlZHVjdGlvbiBpbiBpbmp1cnkgb2Rkcy4gVGhlcmVmb3JlIGJlaW5nIGFib3ZlIHRoZSB0aHJlc2hvbGQgZG9lcyByZWxhdGUgdG8gbG93ZXIgYm9keSByaXNrLg0KYGBge3J9DQojU1RBQ0tFRCBCQVIgQ0hBUlQNCmluanVyeV9jb3VudHMgPC0gYWxsX25vcmRpY19pbmNpZGVudCAlPiUNCiAgbXV0YXRlKA0KICAgIFRocmVzaG9sZCA9IGlmZWxzZShhYm92ZV90aHJlc2hvbGQgPT0gMSwgIuKJpSA1eCBBdGhsZXRlcyBCb2R5d2VpZ2h0IiwgIjwgNXggQXRobGV0ZXMgQm9keXdlaWdodCIpLA0KICAgIEluanVyeSA9IGlmZWxzZShMQi5Jbmp1cnkgPT0gMSwgIkluanVyZWQiLCAiTm90IEluanVyZWQiKQ0KICApICU+JQ0KICBjb3VudChUaHJlc2hvbGQsIEluanVyeSkNCiNQbG90DQpnZ3Bsb3QoaW5qdXJ5X2NvdW50cywgYWVzKHggPSBUaHJlc2hvbGQsIHkgPSBuLCBmaWxsID0gSW5qdXJ5KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAic3RhY2siKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJJbmp1cmVkIj0nI0NGQjg3QycsIk5vdCBJbmp1cmVkIj0nIzAwMDAwMCcpKSsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJMb3dlciBCb2R5IEluanVyeSBDb3VudCBieSBIYW1zdHJpbmcgU3RyZW5ndGggVGhyZXNob2xkIiwNCiAgICB4ID0gIkhhbXN0cmluZyBTdHJlbmd0aCIsDQogICAgeSA9ICJDb3VudCIsDQogICAgZmlsbCA9ICJMb3dlciBCb2R5IEluanVyeSBTdGF0dXMiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KI3Byb3BvcnRpb25zIEdSQVBISUMNCmluanVyeV9wcm9wcyA8LSBhbGxfbm9yZGljX2luY2lkZW50ICU+JQ0KICBtdXRhdGUoDQogICAgVGhyZXNob2xkID0gaWZlbHNlKGFib3ZlX3RocmVzaG9sZCA9PSAxLCAi4omlIDV4IEF0aGxldGVzIEJvZHl3ZWlnaHQiLCAiPCA1eCBBdGhsZXRlcyBCb2R5d2VpZ2h0IiksDQogICAgSW5qdXJ5ID0gaWZlbHNlKExCLkluanVyeSA9PSAxLCAiSW5qdXJlZCIsICJOb3QgSW5qdXJlZCIpDQogICkgJT4lDQogIGNvdW50KFRocmVzaG9sZCwgSW5qdXJ5KSAlPiUNCiAgZ3JvdXBfYnkoVGhyZXNob2xkKSAlPiUNCiAgbXV0YXRlKHByb3AgPSBuIC8gc3VtKG4pKQ0KDQojcGxvdA0KZ2dwbG90KGluanVyeV9wcm9wcywgYWVzKHggPSBUaHJlc2hvbGQsIHkgPSBwcm9wLCBmaWxsID0gSW5qdXJ5KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZmlsbCIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIkluanVyZWQiPScjQ0ZCODdDJywiTm90IEluanVyZWQiPScjMDAwMDAwJykpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdCgpKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUHJvcG9ydGlvbiBvZiBBdGhsZXRlcyB3aXRoIGEgTG93ZXIgQm9keSBJbmp1cnkgdnMgTm8gSW5qdXJ5IGJ5IFRocmVzaG9sZCIsDQogICAgeCA9ICJIYW1zdHJpbmcgU3RyZW5ndGgiLA0KICAgIHkgPSAiUHJvcG9ydGlvbiIsDQogICAgZmlsbCA9ICJMb3dlciBCb2R5SSBuanVyeSBTdGF0dXMiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpDb21iaW5pbmcgZm9yY2VkZWNrcyBkYXRhIHdpdGggaW5jaWRlbnQgZGF0YSB0byBjb21wYXJlIGluanVyaWVzIGFjcm9zcyBhbGwgc3BvcnRzIHdpdGggZm9yY2VkZWNrIHN0cmVuZ3RoIGluZm9ybWF0aW9uLg0KYGBge3J9DQojbWFrZSBhbGwgbWVyZ2luZyBkYXRhc2V0cyB0aGUgc2FtZSAjIGlmIHZhcmlhYmxlcyANCkNNSl9iYiA8LSBDTUpfYmIgJT4lDQogIHNlbGVjdCgtYyhUZXN0LlR5cGUpKQ0KQ01KX3NvYyA8LSBDTUpfc29jICU+JQ0KICBzZWxlY3QoLWMoVGVzdC5UeXBlKSkNCkNNSl9sYXggPC0gQ01KX2xheCAlPiUNCiAgc2VsZWN0KC1jKFRlc3QuVHlwZSkpDQpgYGANCg0KYGBge3J9DQojY3JlYXRlIGEgZGF0YXNldCBjb250YWluaW5nIGFsbCBDTUogdGVzdCBkYXRhIGFjcm9zcyBhbGwgc3BvcnRzDQphbGxfQ01KIDwtIHJiaW5kKENNSl9iYiwgQ01KX3NvYywgQ01KX2xheCwgQ01KX3ZiKSANCmFsbF9DTUpfaW5jaWRlbnQgPC0gbWVyZ2UoYWxsX2luY2lkZW50LCBhbGxfQ01KLGJ5PWMoJ2Fub25faWQnKSwgbmEucm09VFJVRSkgIzM0NzEgdiA2Nw0KDQojY3JlYXRlIGEgZGF0YXNldCBjb250YWluaW5nIGFsbCBISiB0ZXN0IGRhdGEgYWNyb3NzIGFsbCBzcG9ydHMNCmFsbF9ob3BqdW1wIDwtIHJiaW5kKEhKX0IsIEhKX1MsIEhKX0wsIEhKX1YpDQphbGxfaG9wanVtcF9pbmNpZGVudCA8LSBtZXJnZShhbGxfaW5jaWRlbnQsIGFsbF9ob3BqdW1wLGJ5PWMoJ2Fub25faWQnKSwgbmEucm09VFJVRSkgICM1NTk3IHYgNDcNCg0KI2NyZWF0ZSBhIGRhdGFzZXQgY29udGFpbmluZyBhbGwgSU1UUCB0ZXN0IGRhdGEgYWNyb3NzIGFsbCBzcG9ydHMNCmFsbF9JTVRQIDwtIHJiaW5kKElNVFBfQiwgSU1UUF9TLCBJTVRQX0wsIElNVFBfVikNCmFsbF9JTVRQX2luY2lkZW50IDwtIG1lcmdlKGFsbF9pbmNpZGVudCwgYWxsX0lNVFAsYnk9YygnYW5vbl9pZCcpLCBuYS5ybT1UUlVFKSAjMTU1MiB2IDU3DQoNCiNjcmVhdGUgYSBkYXRhc2V0IGNvbnRhaW5pbmcgYWxsIFNMSiB0ZXN0IGRhdGEgYWNyb3NzIGFsbCBzcG9ydHMNCmFsbF9TTEogPC0gcmJpbmQoU0xKX3MsIFNMSl9sKSANCmFsbF9TTEpfaW5jaWRlbnQgPC0gbWVyZ2UoYWxsX2luY2lkZW50LCBhbGxfU0xKLGJ5PWMoJ2Fub25faWQnKSwgbmEucm09VFJVRSkgICM0NjEgdiA1Mg0KYGBgDQoNCiMjRklORElORyBNWSBPV04gVEhSRVNIT0xEUw0KI1ByZWZvcm1hbmNlIGRhdGENCmBgYHtyfQ0KI3dheSB0byBmaW5kIHRocmVzaG9sZA0KYWxsX2hpcF9pbmNpZGVudCRMQi5Jbmp1cnkgPC0gYXMuZmFjdG9yKGFsbF9oaXBfaW5jaWRlbnQkTEIuSW5qdXJ5KQ0KDQpjcCA8LSBjdXRwb2ludHIoYWxsX2hpcF9pbmNpZGVudCwgQmlsYXRlcmFsLkhpcC5BYmR1Y3Rpb24uQWRkdWN0aW9uLlJhdGlvLCBMQi5Jbmp1cnksIG1ldGhvZD1tYXhpbWl6ZV9tZXRyaWMsIG1ldHJpYz15b3VkZW4pDQpwbG90KGNwKQ0Kc3VtbWFyeShjcCkNCmBgYA0KRm9yIEJpbGF0ZXJhbCBoaXAgYWJkdWN0aW9uIGFkZHVjdGlvbiByYXRpbyB0aGUgb3B0aW1hbCBjdXRwb2ludCBpcyAxLjAyNCB3aXRoIGEgQVVDIG9mIDAuNTQ4Miwgc2Vuc2l0aXZpdHkgb2YgMC40ODczIGFuZCBzcGVjaWZpY2l0eSBvZiAwLjY1NjQuDQpgYGB7cn0NCiNvdGhlciB3YXkgdG8gZmluZCB0aHJlc2hvbGQNCiNST0Mgb2JqZWN0DQpyb2Nfb2JqIDwtIHJvYyhyZXNwb25zZSA9IGFsbF9oaXBfaW5jaWRlbnQkTEIuSW5qdXJ5LA0KICAgICAgICAgICAgICAgcHJlZGljdG9yID0gYWxsX2hpcF9pbmNpZGVudCRCaWxhdGVyYWwuSGlwLkFiZHVjdGlvbi5BZGR1Y3Rpb24uUmF0aW8sICNwb3dlcg0KICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gIj4iKSAgIyB1c2UgIjwiIGlmIGhpZ2hlciB2YWx1ZXM9IGhpZ2ggcmlzayBwcmVkaWN0ICdObycNCiAgICAgICAgICAgICAgICMgaWYgPiByZWwuIGNvbi4gcG93ZXIgdGhlbiBsb3dlciByaXNrDQojcGxvdCBjdXJ2ZQ0KcGxvdChyb2Nfb2JqLCBtYWluID0gIlJPQyBDdXJ2ZSAtIEJpbGF0ZXJhbCBIaXAgQWJkdWN0aW9uIEFkZHVjdGlvbi5SYXRpbyIpDQphdWNfdmFsdWUgPC0gYXVjKHJvY19vYmopDQpwcmludChhdWNfdmFsdWUpDQpiZXN0X2Nvb3JkcyA8LSBjb29yZHMocm9jX29iaiwgImJlc3QiLCByZXQgPSBjKCJ0aHJlc2hvbGQiLCAic2Vuc2l0aXZpdHkiLCAic3BlY2lmaWNpdHkiKSwgYmVzdC5tZXRob2QgPSAieW91ZGVuIikNCmJlc3RfY29vcmRzDQoNCiNwbG90ICsgdGhyZXNob2xkDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIHdpdGggT3B0aW1hbCBUaHJlc2hvbGQiKQ0KYWJsaW5lKGEgPSAwLCBiID0gMSwgbHR5ID0gMiwgY29sID0gImdyYXkiKQ0KcG9pbnRzKDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sIGNvbCA9ICcjQ0ZCODdDJywgcGNoID0gMTkpDQp0ZXh0KDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sDQogICAgIGxhYmVscyA9IHBhc3RlKCJUaHJlc2hvbGQgPSIsIHJvdW5kKGJlc3RfY29vcmRzWyJ0aHJlc2hvbGQiXSwgMikpLCBwb3MgPSA0KQ0KYGBgDQpUaGUgQmlsYXRlcmFsIEhpcCBhYmR1Y3Rpb24gYWRkdWN0aW9uIHRocmVzaG9sZCBpcyAxLjAyMzUgd2l0aCBhIHNlbnNpdGl2aXR5IG9mIDAuNjU2NDM2NSBhbmQgYSBzcGVjaWZpY2l0eSBvZiAwLjQ4NzMyMzkgYW5kIGFuIEFVQyBvZiAwLjU0ODINCmBgYHtyfQ0KI2xvb2sgYXQvZGlzY292ZXIvY3JlYXRlIG1vcmUgbWVhbmluZ2Z1bCB0aHJlc2hvbGRzIGZvciBzdHJlbmd0aCBtZXRyaWNzIHJlbGF0aW5nIHRvIExCIGluanVyeSByaXNrLCB0aGVuIHRlc3QgY29uZmlybSB0aHJlc2hvbGQgaXMgdmFsdWFibGUgKyBpbnRlcnByZXQNCmFsbF9oaXBfaW5jaWRlbnQgPC0gIGFsbF9oaXBfaW5jaWRlbnQgJT4lDQogIG11dGF0ZShhYm92ZV90aHJlc2hvbGQ9aWZlbHNlKEJpbGF0ZXJhbC5IaXAuQWJkdWN0aW9uLkFkZHVjdGlvbi5SYXRpbz49IDEuMDI0LCAxLDApKSNhZGQgbmV3Zm91bmQgdGhyZXNob2xkIA0KI0RvZXMgYmVpbmcgYWJvdmUgdGhlIHRocmVzaG9sZCByZWxhdGUgdG8gbG93ZXIgYm9keSBpbmp1cnkgcmlzaz8NCm1vZGVsIDwtIGdsbShMQi5Jbmp1cnl+IGFib3ZlX3RocmVzaG9sZCxkYXRhPWFsbF9oaXBfaW5jaWRlbnQsIGZhbWlseT0iYmlub21pYWwiKQ0Kc3VtbWFyeShtb2RlbCkNCm9kZHMucmF0aW89ZXhwKC0wLjU5Njc0KQ0KKDEtb2Rkcy5yYXRpbykqMTAwDQoNCiNHUkFQSElDUw0KI2RlbnNpdHkgcGxvdA0KZ2dwbG90KGFsbF9oaXBfaW5jaWRlbnQsIGFlcyh4ID0gQmlsYXRlcmFsLkhpcC5BYmR1Y3Rpb24uQWRkdWN0aW9uLlJhdGlvLCBmaWxsID0gTEIuSW5qdXJ5KSkgKw0KICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjQpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMS4wMjQsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIsIHNpemUgPSAxKSArDQogIGxhYnModGl0bGUgPSAiRGVuc2l0eSBQbG90OiBCaWxhdGVyYWwgSGlwIEFiZHVjdGlvbi1BZGR1Y3Rpb24gUmF0aW8gYnkgSW5qdXJ5IFN0YXR1cyIsDQogICAgICAgeCA9ICJCaWxhdGVyYWwgSGlwIEFiZHVjdGlvbi1BZGR1Y3Rpb24gUmF0aW8iLA0KICAgICAgIHkgPSAiRGVuc2l0eSIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiMCIgPSAiIzAwMDAwMCIsICIxIiA9ICIjQ0ZCODdDIiksDQogICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiTG93ZXIgQm9keSBJbmp1cnkiLCBsYWJlbHMgPSBjKCJObyIsICJZZXMiKSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID1jKDAsMykpDQojYm94cGxvdA0KZ2dwbG90KGFsbF9oaXBfaW5jaWRlbnQsIGFlcyh4ID0gTEIuSW5qdXJ5LCB5ID0gQmlsYXRlcmFsLkhpcC5BYmR1Y3Rpb24uQWRkdWN0aW9uLlJhdGlvLCBmaWxsID0gTEIuSW5qdXJ5KSkgKw0KICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjcpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMS4wMjQsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIpICsNCiAgbGFicyh0aXRsZSA9ICJCb3hwbG90OiBCaWxhdGVyYWwgSGlwIEFiZHVjdGlvbi1BZGR1Y3Rpb24gUmF0aW8gYnkgSW5qdXJ5IFN0YXR1cyIsDQogICAgICAgeCA9ICJMb3dlciBCb2R5IEluanVyeSIsIHkgPSAiQmlsYXRlcmFsIEhpcCBBYmR1Y3Rpb24tQWRkdWN0aW9uIFJhdGlvIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIwIiA9ICIjMDAwMDAwIiwgIjEiID0iI0NGQjg3QyIpLA0KICAgICAgICAgICAgICAgICAgICBuYW1lID0gIkxCIEluanVyeSIsIGxhYmVscyA9IGMoIk5vIiwgIlllcyIpKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPWMoMCwzKSkNCg0KI2Fub3RoZXIgY291bnQgZGlzdHJpYnV0aW9uDQppbmp1cnlfY291bnRzIDwtIGFsbF9oaXBfaW5jaWRlbnQgJT4lDQogIG11dGF0ZSgNCiAgICBUaHJlc2hvbGQgPSBpZmVsc2UoYWJvdmVfdGhyZXNob2xkID09IDEsICJBYm92ZSIsICJCZWxvdyIpLA0KICAgIEluanVyeSA9IGlmZWxzZShMQi5Jbmp1cnkgPT0gMSwgIlllcyIsICJObyIpDQogICkgJT4lDQogIGNvdW50KFRocmVzaG9sZCwgSW5qdXJ5KQ0KZ2dwbG90KGluanVyeV9jb3VudHMsIGFlcyh4ID0gVGhyZXNob2xkLCB5ID0gbiwgZmlsbCA9IEluanVyeSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gInN0YWNrIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiWWVzIj0nI0NGQjg3QycsIk5vIj0nIzAwMDAwMCcpKSsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJMb3dlciBCb2R5IEluanVyeSBDb3VudCBBYm92ZSB2cyBCZWxvdyB0aGUgQmlsYXRlcmFsIEhpcCBBYmR1Y3Rpb24tQWRkdWN0aW9uIFRocmVzaG9sZCIsDQogICAgeCA9ICJCaWxhdGVyYWwgSGlwIEFiZHVjdGlvbi1BZGR1Y3Rpb24gUmF0aW8gVGhyZXNob2xkIiwNCiAgICB5ID0gIkNvdW50IiwNCiAgICBmaWxsID0gIkxvd2VyIEJvZHkgSW5qdXJ5Ig0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiNwcm9wb3J0aW9ucyBkaXN0cmlidXRpb24NCnRocmVzaG9sZF9zdW1tYXJ5IDwtIGFsbF9oaXBfaW5jaWRlbnQgJT4lDQogIGdyb3VwX2J5KGFib3ZlX3RocmVzaG9sZCwgTEIuSW5qdXJ5KSAlPiUNCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUNCiAgbXV0YXRlKHByb3AgPSBjb3VudCAvIHN1bShjb3VudCkpDQoNCmdncGxvdCh0aHJlc2hvbGRfc3VtbWFyeSwgYWVzKHggPSBmYWN0b3IoYWJvdmVfdGhyZXNob2xkKSwgeSA9IHByb3AsIGZpbGwgPSBmYWN0b3IoTEIuSW5qdXJ5KSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImZpbGwiKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIjAiID0gIiMwMDAwMDAiLCAiMSIgPSAiI0NGQjg3QyIpLA0KICAgICAgICAgICAgICAgICAgICBuYW1lID0gIkxvd2VyIEJvZHkgSW5qdXJ5IiwgbGFiZWxzID0gYygiTm8iLCAiWWVzIikpICsNCiAgbGFicyh4ID0gIkJpbGF0ZXJhbCBIaXAgQWJkdWN0aW9uLUFkZHVjdGlvbiBSYXRpbyBUaHJlc2hvbGQiLCB5ID0gIlByb3BvcnRpb24iLA0KICAgICAgIHRpdGxlID0gIkxvd2VyIEJvZHkgSW5qdXJ5IFByb3BvcnRpb25zIEFib3ZlIHZzIEJlbG93IHRoZSBCaWxhdGVyYWwgSGlwIEFiZHVjdGlvbi1BZGR1Y3Rpb24gVGhyZXNob2xkIikgKw0KICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoIjAiID0gIkJlbG93IiwgIjEiID0gIkFib3ZlIikpDQpgYGANCg0KYGBge3J9DQojdmFyaWFibGUgSU1QVUxTRQ0KYWxsX2hpcF9pbmNpZGVudCRMQi5Jbmp1cnkgPC0gYXMuZmFjdG9yKGFsbF9oaXBfaW5jaWRlbnQkTEIuSW5qdXJ5KQ0KDQpjcCA8LSBjdXRwb2ludHIoYWxsX2hpcF9pbmNpZGVudCwgSW1wdWxzZSwgTEIuSW5qdXJ5LCBtZXRob2Q9bWF4aW1pemVfbWV0cmljLCBtZXRyaWM9eW91ZGVuKQ0KcGxvdChjcCkNCnN1bW1hcnkoY3ApDQpgYGANCkZvciBJbXB1bHNlIHRoZSBvcHRpbWFsIGN1dHBvaW50IGlzIDI2OTkuOTc1IHdpdGggYSBBVUMgb2YgMC41MTE0LCBzZW5zaXRpdml0eSBvZiAwLjIxNCBhbmQgc3BlY2lmaWNpdHkgb2YgMC44NDUxLg0KYGBge3J9DQojb3RoZXIgd2F5IHRvIGZpbmQgdGhyZXNob2xkIA0KI1JPQyBvYmplY3QNCnJvY19vYmogPC0gcm9jKHJlc3BvbnNlID0gYWxsX2hpcF9pbmNpZGVudCRMQi5Jbmp1cnksDQogICAgICAgICAgICAgICBwcmVkaWN0b3IgPSBhbGxfaGlwX2luY2lkZW50JEltcHVsc2UsICNwb3dlcg0KICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gIj4iKSAgIyB1c2UgIjwiIGlmIGhpZ2hlciB2YWx1ZXM9IGhpZ2ggcmlzayBwcmVkaWN0ICdObycNCiAgICAgICAgICAgICAgICMgaWYgPiByZWwuIGNvbi4gcG93ZXIgdGhlbiBsb3dlciByaXNrDQojcGxvdCBjdXJ2ZQ0KcGxvdChyb2Nfb2JqLCBtYWluID0gIlJPQyBDdXJ2ZSAtIEltcHVsc2UiKQ0KYXVjX3ZhbHVlIDwtIGF1Yyhyb2Nfb2JqKQ0KcHJpbnQoYXVjX3ZhbHVlKQ0KYmVzdF9jb29yZHMgPC0gY29vcmRzKHJvY19vYmosICJiZXN0IiwgcmV0ID0gYygidGhyZXNob2xkIiwgInNlbnNpdGl2aXR5IiwgInNwZWNpZmljaXR5IiksIGJlc3QubWV0aG9kID0gInlvdWRlbiIpDQpiZXN0X2Nvb3Jkcw0KDQojcGxvdCArIHRocmVzaG9sZA0KcGxvdChyb2Nfb2JqLCBtYWluID0gIlJPQyBDdXJ2ZSB3aXRoIE9wdGltYWwgVGhyZXNob2xkIikNCmFibGluZShhID0gMCwgYiA9IDEsIGx0eSA9IDIsIGNvbCA9ICJncmF5IikNCnBvaW50cygxIC0gYmVzdF9jb29yZHNbInNwZWNpZmljaXR5Il0sIGJlc3RfY29vcmRzWyJzZW5zaXRpdml0eSJdLCBjb2wgPSAnI0NGQjg3QycsIHBjaCA9IDE5KQ0KdGV4dCgxIC0gYmVzdF9jb29yZHNbInNwZWNpZmljaXR5Il0sIGJlc3RfY29vcmRzWyJzZW5zaXRpdml0eSJdLA0KICAgICBsYWJlbHMgPSBwYXN0ZSgiVGhyZXNob2xkID0iLCByb3VuZChiZXN0X2Nvb3Jkc1sidGhyZXNob2xkIl0sIDIpKSwgcG9zID0gNCkNCmBgYA0KVGhlIEltcHVsc2UgdGhyZXNob2xkIGlzIDk3My4xNzc1IHdpdGggYSBzZW5zaXRpdml0eSBvZiAwLjA3NTg3MzgzCSBhbmQgYSBzcGVjaWZpY2l0eSBvZiAwLjk1Nzc0NjUgYW5kIGFuIEFVQyBvZiAwLjQ4ODYuDQpgYGB7cn0NCiNsb29rIGF0L2Rpc2NvdmVyL2NyZWF0ZSBtb3JlIG1lYW5pbmdmdWwgdGhyZXNob2xkcyBmb3Igc3RyZW5ndGggbWV0cmljcyByZWxhdGluZyB0byBMQiBpbmp1cnkgcmlzaywgdGhlbiB0ZXN0IGNvbmZpcm0gdGhyZXNob2xkIGlzIHZhbHVhYmxlICsgaW50ZXJwcmV0ICAgICMyNjk5Ljk3NQ0KYWxsX2hpcF9pbmNpZGVudCA8LSAgYWxsX2hpcF9pbmNpZGVudCAlPiUNCiAgbXV0YXRlKGFib3ZlX3RocmVzaG9sZD1pZmVsc2UoSW1wdWxzZT49IDk3My4xNzc1LCAxLDApKSNhZGQgbmV3Zm91bmQgdGhyZXNob2xkIA0KI0RvZXMgYmVpbmcgYWJvdmUgdGhlIHRocmVzaG9sZCByZWxhdGUgdG8gbG93ZXIgYm9keSBpbmp1cnkgcmlzaz8NCm1vZGVsIDwtIGdsbShMQi5Jbmp1cnl+IGFib3ZlX3RocmVzaG9sZCxkYXRhPWFsbF9oaXBfaW5jaWRlbnQsIGZhbWlseT0iYmlub21pYWwiKQ0Kc3VtbWFyeShtb2RlbCkNCm9kZHMucmF0aW89ZXhwKC0wLjYyMTEpDQooMS1vZGRzLnJhdGlvKSoxMDANCg0KI0dSQVBISUNTDQojZGVuc2l0eSBwbG90DQpnZ3Bsb3QoYWxsX2hpcF9pbmNpZGVudCwgYWVzKHggPSBJbXB1bHNlLCBmaWxsID0gTEIuSW5qdXJ5KSkgKw0KICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjQpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gOTczLjE3NzUsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIsIHNpemUgPSAxKSArDQogIGxhYnModGl0bGUgPSAiRGVuc2l0eSBQbG90OiBJbXB1bHNlIGJ5IEluanVyeSBTdGF0dXMiLA0KICAgICAgIHggPSAiSW1wdWxzZSIsDQogICAgICAgeSA9ICJEZW5zaXR5IikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIwIiA9ICIjMDAwMDAwIiwgIjEiID0gIiNDRkI4N0MiKSwNCiAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJMb3dlciBCb2R5IEluanVyeSIsIGxhYmVscyA9IGMoIk5vIiwgIlllcyIpKSAjKw0KICAjc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9YygwLDMpKQ0KI2JveHBsb3QNCmdncGxvdChhbGxfaGlwX2luY2lkZW50LCBhZXMoeCA9IExCLkluanVyeSwgeSA9IEltcHVsc2UsIGZpbGwgPSBMQi5Jbmp1cnkpKSArDQogIGdlb21fYm94cGxvdChhbHBoYSA9IDAuNykgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSA5NzMuMTc3NSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIikgKw0KICBsYWJzKHRpdGxlID0gIkJveHBsb3Q6IEltcHVsc2UgYnkgSW5qdXJ5IFN0YXR1cyIsDQogICAgICAgeCA9ICJMb3dlciBCb2R5IEluanVyeSIsIHkgPSAiSW1wdWxzZSIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiMCIgPSAiIzAwMDAwMCIsICIxIiA9IiNDRkI4N0MiKSwNCiAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJMQiBJbmp1cnkiLCBsYWJlbHMgPSBjKCJObyIsICJZZXMiKSkjICsNCiAgI3NjYWxlX3lfY29udGludW91cyhsaW1pdHMgPWMoMCwzKSkNCg0KI2NvdW50IGRpc3RyaWJ1dGlvbg0KaW5qdXJ5X2NvdW50cyA8LSBhbGxfaGlwX2luY2lkZW50ICU+JQ0KICBtdXRhdGUoDQogICAgVGhyZXNob2xkID0gaWZlbHNlKGFib3ZlX3RocmVzaG9sZCA9PSAxLCAiQWJvdmUiLCAiQmVsb3ciKSwNCiAgICBJbmp1cnkgPSBpZmVsc2UoTEIuSW5qdXJ5ID09IDEsICJZZXMiLCAiTm8iKQ0KICApICU+JQ0KICBjb3VudChUaHJlc2hvbGQsIEluanVyeSkNCmdncGxvdChpbmp1cnlfY291bnRzLCBhZXMoeCA9IFRocmVzaG9sZCwgeSA9IG4sIGZpbGwgPSBJbmp1cnkpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJzdGFjayIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIlllcyI9JyNDRkI4N0MnLCJObyI9JyMwMDAwMDAnKSkrDQogIGxhYnMoDQogICAgdGl0bGUgPSAiTG93ZXIgQm9keSBJbmp1cnkgQ291bnQgQWJvdmUgdnMgQmVsb3cgdGhlIEltcHVsc2UgVGhyZXNob2xkIiwNCiAgICB4ID0gIkltcHVsc2UgVGhyZXNob2xkIiwNCiAgICB5ID0gIkNvdW50IiwNCiAgICBmaWxsID0gIkxvd2VyIEJvZHkgSW5qdXJ5Ig0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiNwcm9wb3J0aW9ucyBkaXN0cmlidXRpb24NCnRocmVzaG9sZF9zdW1tYXJ5IDwtIGFsbF9oaXBfaW5jaWRlbnQgJT4lDQogIGdyb3VwX2J5KGFib3ZlX3RocmVzaG9sZCwgTEIuSW5qdXJ5KSAlPiUNCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUNCiAgbXV0YXRlKHByb3AgPSBjb3VudCAvIHN1bShjb3VudCkpDQoNCmdncGxvdCh0aHJlc2hvbGRfc3VtbWFyeSwgYWVzKHggPSBmYWN0b3IoYWJvdmVfdGhyZXNob2xkKSwgeSA9IHByb3AsIGZpbGwgPSBmYWN0b3IoTEIuSW5qdXJ5KSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImZpbGwiKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIjAiID0gIiMwMDAwMDAiLCAiMSIgPSAiI0NGQjg3QyIpLA0KICAgICAgICAgICAgICAgICAgICBuYW1lID0gIkxvd2VyIEJvZHkgSW5qdXJ5IiwgbGFiZWxzID0gYygiTm8iLCAiWWVzIikpICsNCiAgbGFicyh4ID0gIkltcHVsc2UgVGhyZXNob2xkIiwgeSA9ICJQcm9wb3J0aW9uIiwNCiAgICAgICB0aXRsZSA9ICJMb3dlciBCb2R5IEluanVyeSBQcm9wb3J0aW9ucyBBYm92ZSB2cyBCZWxvdyB0aGUgSW1wdWxzZSBUaHJlc2hvbGQiKSArDQogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gYygiMCIgPSAiQmVsb3ciLCAiMSIgPSAiQWJvdmUiKSkNCmBgYA0KDQojSGlwLkFiZHVjdGlvbg0KYGBge3J9DQphbGxfaGlwX2luY2lkZW50JExCLkluanVyeSA8LSBhcy5mYWN0b3IoYWxsX2hpcF9pbmNpZGVudCRMQi5Jbmp1cnkpDQoNCmNwIDwtIGN1dHBvaW50cihhbGxfaGlwX2luY2lkZW50LCBIaXAuQWJkdWN0aW9uLk1FQU4uSW1iYWxhbmNlLCBMQi5Jbmp1cnksIG1ldGhvZD1tYXhpbWl6ZV9tZXRyaWMsIG1ldHJpYz15b3VkZW4pDQpwbG90KGNwKQ0Kc3VtbWFyeShjcCkNCmBgYA0KRm9yIEhpcCBBYmR1Y3Rpb24gTUVBTiBJbWJhbGFuY2UgdGhlIG9wdGltYWwgY3V0cG9pbnQgaXMgMS40IHdpdGggYSBBVUMgb2YgMC41MTQzLCBzZW5zaXRpdml0eSBvZiAwLjg2MDIgYW5kIHNwZWNpZmljaXR5IG9mIDAuMTk0NC4NCmBgYHtyfQ0KI290aGVyIHdheSB0byBmaW5kIHRocmVzaG9sZCANCiNST0Mgb2JqZWN0DQpyb2Nfb2JqIDwtIHJvYyhyZXNwb25zZSA9IGFsbF9oaXBfaW5jaWRlbnQkTEIuSW5qdXJ5LA0KICAgICAgICAgICAgICAgcHJlZGljdG9yID0gYWxsX2hpcF9pbmNpZGVudCRIaXAuQWJkdWN0aW9uLk1FQU4uSW1iYWxhbmNlLCAjcG93ZXINCiAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICI+IikgICMgdXNlICI8IiBpZiBoaWdoZXIgdmFsdWVzPSBoaWdoIHJpc2sgcHJlZGljdCAnTm8nDQogICAgICAgICAgICAgICAjIGlmID4gcmVsLiBjb24uIHBvd2VyIHRoZW4gbG93ZXIgcmlzaw0KI3Bsb3QgY3VydmUNCnBsb3Qocm9jX29iaiwgbWFpbiA9ICJST0MgQ3VydmUgLSBIaXAuQWJkdWN0aW9uLk1FQU4uSW1iYWxhbmNlIikNCmF1Y192YWx1ZSA8LSBhdWMocm9jX29iaikNCnByaW50KGF1Y192YWx1ZSkNCmJlc3RfY29vcmRzIDwtIGNvb3Jkcyhyb2Nfb2JqLCAiYmVzdCIsIHJldCA9IGMoInRocmVzaG9sZCIsICJzZW5zaXRpdml0eSIsICJzcGVjaWZpY2l0eSIpLCBiZXN0Lm1ldGhvZCA9ICJ5b3VkZW4iKQ0KYmVzdF9jb29yZHMNCg0KI3Bsb3QgKyB0aHJlc2hvbGQNCnBsb3Qocm9jX29iaiwgbWFpbiA9ICJST0MgQ3VydmUgd2l0aCBPcHRpbWFsIFRocmVzaG9sZCIpDQphYmxpbmUoYSA9IDAsIGIgPSAxLCBsdHkgPSAyLCBjb2wgPSAiZ3JheSIpDQpwb2ludHMoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwgY29sID0gJyNDRkI4N0MnLCBwY2ggPSAxOSkNCnRleHQoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwNCiAgICAgbGFiZWxzID0gcGFzdGUoIlRocmVzaG9sZCA9Iiwgcm91bmQoYmVzdF9jb29yZHNbInRocmVzaG9sZCJdLCAyKSksIHBvcyA9IDQpDQpgYGANClRoZSBIaXAuQWJkdWN0aW9uLk1FQU4uSW1iYWxhbmNlIHRocmVzaG9sZCBpcyA1LjE1IHdpdGggYSBzZW5zaXRpdml0eSBvZiAwLjY0MTk0MzcgYW5kIGEgc3BlY2lmaWNpdHkgb2YgMC4zOTE1NDkzCSBhbmQgYW4gQVVDIG9mIDAuNDg1Ny4NCmBgYHtyfQ0KI2xvb2sgYXQvZGlzY292ZXIvY3JlYXRlIG1vcmUgbWVhbmluZ2Z1bCB0aHJlc2hvbGRzIGZvciBzdHJlbmd0aCBtZXRyaWNzIHJlbGF0aW5nIHRvIExCIGluanVyeSByaXNrLCB0aGVuIHRlc3QgY29uZmlybSB0aHJlc2hvbGQgaXMgdmFsdWFibGUgKyBpbnRlcnByZXQgICANCmFsbF9oaXBfaW5jaWRlbnQgPC0gIGFsbF9oaXBfaW5jaWRlbnQgJT4lDQogIG11dGF0ZShhYm92ZV90aHJlc2hvbGQ9aWZlbHNlKEhpcC5BYmR1Y3Rpb24uTUVBTi5JbWJhbGFuY2U+PSAxLjQsIDEsMCkpI2FkZCBuZXdmb3VuZCB0aHJlc2hvbGQgDQojRG9lcyBiZWluZyBhYm92ZSB0aGUgdGhyZXNob2xkIHJlbGF0ZSB0byBsb3dlciBib2R5IGluanVyeSByaXNrPw0KbW9kZWwgPC0gZ2xtKExCLkluanVyeX4gYWJvdmVfdGhyZXNob2xkLGRhdGE9YWxsX2hpcF9pbmNpZGVudCwgZmFtaWx5PSJiaW5vbWlhbCIpDQpzdW1tYXJ5KG1vZGVsKQ0KZXhwKDAuMzk1MCkNCg0KI0dSQVBISUNTDQojZGVuc2l0eSBwbG90DQpnZ3Bsb3QoYWxsX2hpcF9pbmNpZGVudCwgYWVzKHggPSBIaXAuQWJkdWN0aW9uLk1FQU4uSW1iYWxhbmNlLCBmaWxsID0gTEIuSW5qdXJ5KSkgKw0KICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjQpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMS40LCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiLCBzaXplID0gMSkgKw0KICBsYWJzKHRpdGxlID0gIkRlbnNpdHkgUGxvdDogSGlwIEFiZHVjdGlvbiBNZWFuIEltYmFsYW5jZSBieSBJbmp1cnkgU3RhdHVzIiwNCiAgICAgICB4ID0gIkhpcCBBYmR1Y3Rpb24gTWVhbiBJbWJhbGFuY2UiLA0KICAgICAgIHkgPSAiRGVuc2l0eSIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiMCIgPSAiIzAwMDAwMCIsICIxIiA9ICIjQ0ZCODdDIiksDQogICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiTG93ZXIgQm9keSBJbmp1cnkiLCBsYWJlbHMgPSBjKCJObyIsICJZZXMiKSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID1jKDAsMzApKQ0KI2JveHBsb3QNCmdncGxvdChhbGxfaGlwX2luY2lkZW50LCBhZXMoeCA9IExCLkluanVyeSwgeSA9IEhpcC5BYmR1Y3Rpb24uTUVBTi5JbWJhbGFuY2UsIGZpbGwgPSBMQi5Jbmp1cnkpKSArDQogIGdlb21fYm94cGxvdChhbHBoYSA9IDAuNykgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxLjQsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIpICsNCiAgbGFicyh0aXRsZSA9ICJCb3hwbG90OiBIaXAgQWJkdWN0aW9uIE1lYW4gSW1iYWxhbmNlIGJ5IEluanVyeSBTdGF0dXMiLA0KICAgICAgIHggPSAiTG93ZXIgQm9keSBJbmp1cnkiLCB5ID0gIkhpcCBBYmR1Y3Rpb24gTWVhbiBJbWJhbGFuY2UiKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIjAiID0gIiMwMDAwMDAiLCAiMSIgPSIjQ0ZCODdDIiksDQogICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiTEIgSW5qdXJ5IiwgbGFiZWxzID0gYygiTm8iLCAiWWVzIikpIyArDQogICNzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID1jKDAsMykpDQoNCiNjb3VudCBkaXN0cmlidXRpb24NCmluanVyeV9jb3VudHMgPC0gYWxsX2hpcF9pbmNpZGVudCAlPiUNCiAgbXV0YXRlKA0KICAgIFRocmVzaG9sZCA9IGlmZWxzZShhYm92ZV90aHJlc2hvbGQgPT0gMSwgIkFib3ZlIiwgIkJlbG93IiksDQogICAgSW5qdXJ5ID0gaWZlbHNlKExCLkluanVyeSA9PSAxLCAiWWVzIiwgIk5vIikNCiAgKSAlPiUNCiAgY291bnQoVGhyZXNob2xkLCBJbmp1cnkpDQpnZ3Bsb3QoaW5qdXJ5X2NvdW50cywgYWVzKHggPSBUaHJlc2hvbGQsIHkgPSBuLCBmaWxsID0gSW5qdXJ5KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAic3RhY2siKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJZZXMiPScjQ0ZCODdDJywiTm8iPScjMDAwMDAwJykpKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkxvd2VyIEJvZHkgSW5qdXJ5IENvdW50IEFib3ZlIHZzIEJlbG93IHRoZSBIaXAgQWJkdWN0aW9uIE1lYW4gSW1iYWxhbmNlIFRocmVzaG9sZCIsDQogICAgeCA9ICJIaXAgQWJkdWN0aW9uIE1lYW4gSW1iYWxhbmNlIFRocmVzaG9sZCIsDQogICAgeSA9ICJDb3VudCIsDQogICAgZmlsbCA9ICJMb3dlciBCb2R5IEluanVyeSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQojcHJvcG9ydGlvbnMgZGlzdHJpYnV0aW9uDQp0aHJlc2hvbGRfc3VtbWFyeSA8LSBhbGxfaGlwX2luY2lkZW50ICU+JQ0KICBncm91cF9ieShhYm92ZV90aHJlc2hvbGQsIExCLkluanVyeSkgJT4lDQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lDQogIG11dGF0ZShwcm9wID0gY291bnQgLyBzdW0oY291bnQpKQ0KDQpnZ3Bsb3QodGhyZXNob2xkX3N1bW1hcnksIGFlcyh4ID0gZmFjdG9yKGFib3ZlX3RocmVzaG9sZCksIHkgPSBwcm9wLCBmaWxsID0gZmFjdG9yKExCLkluanVyeSkpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJmaWxsIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIwIiA9ICIjMDAwMDAwIiwgIjEiID0gIiNDRkI4N0MiKSwNCiAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJMb3dlciBCb2R5IEluanVyeSIsIGxhYmVscyA9IGMoIk5vIiwgIlllcyIpKSArDQogIGxhYnMoeCA9ICJIaXAgQWJkdWN0aW9uIE1lYW4gSW1iYWxhbmNlIFRocmVzaG9sZCIsIHkgPSAiUHJvcG9ydGlvbiIsDQogICAgICAgdGl0bGUgPSAiTG93ZXIgQm9keSBJbmp1cnkgUHJvcG9ydGlvbnMgQWJvdmUgdnMgQmVsb3cgdGhlIEhpcCBBYmR1Y3Rpb24gTWVhbiBJbWJhbGFuY2UgVGhyZXNob2xkIikgKw0KICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoIjAiID0gIkJlbG93IiwgIjEiID0gIkFib3ZlIikpDQpgYGANCg0KI0hpcC5BZGR1Y3Rpb24NCmBgYHtyfQ0KYWxsX2hpcF9pbmNpZGVudCRMQi5Jbmp1cnkgPC0gYXMuZmFjdG9yKGFsbF9oaXBfaW5jaWRlbnQkTEIuSW5qdXJ5KQ0KDQpjcCA8LSBjdXRwb2ludHIoYWxsX2hpcF9pbmNpZGVudCwgSGlwLkFkZHVjdGlvbi5NRUFOLkltYmFsYW5jZSwgTEIuSW5qdXJ5LCBtZXRob2Q9bWF4aW1pemVfbWV0cmljLCBtZXRyaWM9eW91ZGVuKQ0KcGxvdChjcCkNCnN1bW1hcnkoY3ApDQpgYGANCkZvciBIaXAgQWRkdWN0aW9uIE1FQU4gSW1iYWxhbmNlIHRoZSBvcHRpbWFsIGN1dHBvaW50IGlzIDQuNSB3aXRoIGEgQVVDIG9mIDAuNTEwNywgc2Vuc2l0aXZpdHkgb2YgMC40OTAyIGFuZCBzcGVjaWZpY2l0eSBvZiAwLjU5MTUuDQpgYGB7cn0NCiNvdGhlciB3YXkgdG8gZmluZCB0aHJlc2hvbGQgDQojUk9DIG9iamVjdA0Kcm9jX29iaiA8LSByb2MocmVzcG9uc2UgPSBhbGxfaGlwX2luY2lkZW50JExCLkluanVyeSwNCiAgICAgICAgICAgICAgIHByZWRpY3RvciA9IGFsbF9oaXBfaW5jaWRlbnQkSGlwLkFkZHVjdGlvbi5NRUFOLkltYmFsYW5jZSwgI3Bvd2VyDQogICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiPiIpICAjIHVzZSAiPCIgaWYgaGlnaGVyIHZhbHVlcz0gaGlnaCByaXNrIHByZWRpY3QgJ05vJw0KICAgICAgICAgICAgICAgIyBpZiA+IHJlbC4gY29uLiBwb3dlciB0aGVuIGxvd2VyIHJpc2sNCiNwbG90IGN1cnZlDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIC0gSGlwLkFkZHVjdGlvbi5NRUFOLkltYmFsYW5jZSIpDQphdWNfdmFsdWUgPC0gYXVjKHJvY19vYmopDQpwcmludChhdWNfdmFsdWUpDQpiZXN0X2Nvb3JkcyA8LSBjb29yZHMocm9jX29iaiwgImJlc3QiLCByZXQgPSBjKCJ0aHJlc2hvbGQiLCAic2Vuc2l0aXZpdHkiLCAic3BlY2lmaWNpdHkiKSwgYmVzdC5tZXRob2QgPSAieW91ZGVuIikNCmJlc3RfY29vcmRzDQoNCiNwbG90ICsgdGhyZXNob2xkDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIHdpdGggT3B0aW1hbCBUaHJlc2hvbGQiKQ0KYWJsaW5lKGEgPSAwLCBiID0gMSwgbHR5ID0gMiwgY29sID0gImdyYXkiKQ0KcG9pbnRzKDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sIGNvbCA9ICcjQ0ZCODdDJywgcGNoID0gMTkpDQp0ZXh0KDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sDQogICAgIGxhYmVscyA9IHBhc3RlKCJUaHJlc2hvbGQgPSIsIHJvdW5kKGJlc3RfY29vcmRzWyJ0aHJlc2hvbGQiXSwgMikpLCBwb3MgPSA0KQ0KYGBgDQpUaGUgSGlwLkFkZHVjdGlvbi5NRUFOLkltYmFsYW5jZSB0aHJlc2hvbGQgaXMgMTYuMiB3aXRoIGEgc2Vuc2l0aXZpdHkgb2YgMC45ODIwOTcyIGFuZCBhIHNwZWNpZmljaXR5IG9mIDAuMDUwNzA0MjMgYW5kIGFuIEFVQyBvZiAwLjQ4OTMuDQpgYGB7cn0NCiNsb29rIGF0L2Rpc2NvdmVyL2NyZWF0ZSBtb3JlIG1lYW5pbmdmdWwgdGhyZXNob2xkcyBmb3Igc3RyZW5ndGggbWV0cmljcyByZWxhdGluZyB0byBMQiBpbmp1cnkgcmlzaywgdGhlbiB0ZXN0IGNvbmZpcm0gdGhyZXNob2xkIGlzIHZhbHVhYmxlICsgaW50ZXJwcmV0ICAgDQphbGxfaGlwX2luY2lkZW50IDwtICBhbGxfaGlwX2luY2lkZW50ICU+JQ0KICBtdXRhdGUoYWJvdmVfdGhyZXNob2xkPWlmZWxzZShIaXAuQWRkdWN0aW9uLk1FQU4uSW1iYWxhbmNlPj0gNC41LCAxLDApKSNhZGQgbmV3Zm91bmQgdGhyZXNob2xkIA0KI0RvZXMgYmVpbmcgYWJvdmUgdGhlIHRocmVzaG9sZCByZWxhdGUgdG8gbG93ZXIgYm9keSBpbmp1cnkgcmlzaz8NCm1vZGVsIDwtIGdsbShMQi5Jbmp1cnl+IGFib3ZlX3RocmVzaG9sZCxkYXRhPWFsbF9oaXBfaW5jaWRlbnQsIGZhbWlseT0iYmlub21pYWwiKQ0Kc3VtbWFyeShtb2RlbCkNCmV4cCgwLjMzMTE1KQ0KDQojR1JBUEhJQ1MNCiNkZW5zaXR5IHBsb3QNCmdncGxvdChhbGxfaGlwX2luY2lkZW50LCBhZXMoeCA9IEhpcC5BZGR1Y3Rpb24uTUVBTi5JbWJhbGFuY2UsIGZpbGwgPSBMQi5Jbmp1cnkpKSArDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNCkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA0LjUsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIsIHNpemUgPSAxKSArDQogIGxhYnModGl0bGUgPSAiRGVuc2l0eSBQbG90OiBIaXAgQWRkdWN0aW9uIE1lYW4gSW1iYWxhbmNlIGJ5IEluanVyeSBTdGF0dXMiLA0KICAgICAgIHggPSAiSGlwIEFkZHVjdGlvbiBNZWFuIEltYmFsYW5jZSIsDQogICAgICAgeSA9ICJEZW5zaXR5IikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIwIiA9ICIjMDAwMDAwIiwgIjEiID0gIiNDRkI4N0MiKSwNCiAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJMb3dlciBCb2R5IEluanVyeSIsIGxhYmVscyA9IGMoIk5vIiwgIlllcyIpKSArDQogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPWMoMCwzNSkpDQojYm94cGxvdA0KZ2dwbG90KGFsbF9oaXBfaW5jaWRlbnQsIGFlcyh4ID0gTEIuSW5qdXJ5LCB5ID0gSGlwLkFkZHVjdGlvbi5NRUFOLkltYmFsYW5jZSwgZmlsbCA9IExCLkluanVyeSkpICsNCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC43KSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDQuNSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIikgKw0KICBsYWJzKHRpdGxlID0gIkJveHBsb3Q6IEhpcCBBZGR1Y3Rpb24gTWVhbiBJbWJhbGFuY2UgYnkgSW5qdXJ5IFN0YXR1cyIsDQogICAgICAgeCA9ICJMb3dlciBCb2R5IEluanVyeSIsIHkgPSAiSGlwIEFkZHVjdGlvbiBNZWFuIEltYmFsYW5jZSIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiMCIgPSAiIzAwMDAwMCIsICIxIiA9IiNDRkI4N0MiKSwNCiAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJMQiBJbmp1cnkiLCBsYWJlbHMgPSBjKCJObyIsICJZZXMiKSkjICsNCiAgI3NjYWxlX3lfY29udGludW91cyhsaW1pdHMgPWMoMCwzKSkNCg0KI2NvdW50IGRpc3RyaWJ1dGlvbg0KaW5qdXJ5X2NvdW50cyA8LSBhbGxfaGlwX2luY2lkZW50ICU+JQ0KICBtdXRhdGUoDQogICAgVGhyZXNob2xkID0gaWZlbHNlKGFib3ZlX3RocmVzaG9sZCA9PSAxLCAiQWJvdmUiLCAiQmVsb3ciKSwNCiAgICBJbmp1cnkgPSBpZmVsc2UoTEIuSW5qdXJ5ID09IDEsICJZZXMiLCAiTm8iKQ0KICApICU+JQ0KICBjb3VudChUaHJlc2hvbGQsIEluanVyeSkNCmdncGxvdChpbmp1cnlfY291bnRzLCBhZXMoeCA9IFRocmVzaG9sZCwgeSA9IG4sIGZpbGwgPSBJbmp1cnkpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJzdGFjayIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIlllcyI9JyNDRkI4N0MnLCJObyI9JyMwMDAwMDAnKSkrDQogIGxhYnMoDQogICAgdGl0bGUgPSAiTG93ZXIgQm9keSBJbmp1cnkgQ291bnQgQWJvdmUgdnMgQmVsb3cgdGhlIEhpcCBBZGR1Y3Rpb24gTWVhbiBJbWJhbGFuY2UgVGhyZXNob2xkIiwNCiAgICB4ID0gIkhpcCBBZGR1Y3Rpb24gTWVhbiBJbWJhbGFuY2UgVGhyZXNob2xkIiwNCiAgICB5ID0gIkNvdW50IiwNCiAgICBmaWxsID0gIkxvd2VyIEJvZHkgSW5qdXJ5Ig0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiNwcm9wb3J0aW9ucyBkaXN0cmlidXRpb24NCnRocmVzaG9sZF9zdW1tYXJ5IDwtIGFsbF9oaXBfaW5jaWRlbnQgJT4lDQogIGdyb3VwX2J5KGFib3ZlX3RocmVzaG9sZCwgTEIuSW5qdXJ5KSAlPiUNCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUNCiAgbXV0YXRlKHByb3AgPSBjb3VudCAvIHN1bShjb3VudCkpDQoNCmdncGxvdCh0aHJlc2hvbGRfc3VtbWFyeSwgYWVzKHggPSBmYWN0b3IoYWJvdmVfdGhyZXNob2xkKSwgeSA9IHByb3AsIGZpbGwgPSBmYWN0b3IoTEIuSW5qdXJ5KSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImZpbGwiKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIjAiID0gIiMwMDAwMDAiLCAiMSIgPSAiI0NGQjg3QyIpLA0KICAgICAgICAgICAgICAgICAgICBuYW1lID0gIkxvd2VyIEJvZHkgSW5qdXJ5IiwgbGFiZWxzID0gYygiTm8iLCAiWWVzIikpICsNCiAgbGFicyh4ID0gIkhpcCBBZGR1Y3Rpb24gTWVhbiBJbWJhbGFuY2UgVGhyZXNob2xkIiwgeSA9ICJQcm9wb3J0aW9uIiwNCiAgICAgICB0aXRsZSA9ICJMb3dlciBCb2R5IEluanVyeSBQcm9wb3J0aW9ucyBBYm92ZSB2cyBCZWxvdyB0aGUgSGlwIEFkZHVjdGlvbiBNZWFuIEltYmFsYW5jZSBUaHJlc2hvbGQiKSArDQogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gYygiMCIgPSAiQmVsb3ciLCAiMSIgPSAiQWJvdmUiKSkNCmBgYA0KDQojTk9SRElDDQpgYGB7cn0NCmFsbF9ub3JkaWNfaW5jaWRlbnQkTEIuSW5qdXJ5IDwtIGFzLmZhY3RvcihhbGxfbm9yZGljX2luY2lkZW50JExCLkluanVyeSkNCg0KY3AgPC0gY3V0cG9pbnRyKGFsbF9ub3JkaWNfaW5jaWRlbnQsIE1heGltdW0uTm9yZGljLkJpbGF0ZXJhbC5NZWFuLCBMQi5Jbmp1cnksIG1ldGhvZD1tYXhpbWl6ZV9tZXRyaWMsIG1ldHJpYz15b3VkZW4pDQpwbG90KGNwKQ0Kc3VtbWFyeShjcCkNCmBgYA0KDQpgYGB7cn0NCiNvdGhlciB3YXkgdG8gZmluZCB0aHJlc2hvbGQgDQojUk9DIG9iamVjdA0Kcm9jX29iaiA8LSByb2MocmVzcG9uc2UgPSBhbGxfbm9yZGljX2luY2lkZW50JExCLkluanVyeSwNCiAgICAgICAgICAgICAgIHByZWRpY3RvciA9IGFsbF9ub3JkaWNfaW5jaWRlbnQkTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4sICNwb3dlcg0KICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gIj4iKSAgIyB1c2UgIjwiIGlmIGhpZ2hlciB2YWx1ZXM9IGhpZ2ggcmlzayBwcmVkaWN0ICdObycNCiAgICAgICAgICAgICAgICMgaWYgPiByZWwuIGNvbi4gcG93ZXIgdGhlbiBsb3dlciByaXNrDQojcGxvdCBjdXJ2ZQ0KcGxvdChyb2Nfb2JqLCBtYWluID0gIlJPQyBDdXJ2ZSAtIE1heGltdW0uTm9yZGljLkJpbGF0ZXJhbC5NZWFuIikNCmF1Y192YWx1ZSA8LSBhdWMocm9jX29iaikNCnByaW50KGF1Y192YWx1ZSkNCmJlc3RfY29vcmRzIDwtIGNvb3Jkcyhyb2Nfb2JqLCAiYmVzdCIsIHJldCA9IGMoInRocmVzaG9sZCIsICJzZW5zaXRpdml0eSIsICJzcGVjaWZpY2l0eSIpLCBiZXN0Lm1ldGhvZCA9ICJ5b3VkZW4iKQ0KYmVzdF9jb29yZHMNCg0KI3Bsb3QgKyB0aHJlc2hvbGQNCnBsb3Qocm9jX29iaiwgbWFpbiA9ICJST0MgQ3VydmUgd2l0aCBPcHRpbWFsIFRocmVzaG9sZCIpDQphYmxpbmUoYSA9IDAsIGIgPSAxLCBsdHkgPSAyLCBjb2wgPSAiZ3JheSIpDQpwb2ludHMoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwgY29sID0gJyNDRkI4N0MnLCBwY2ggPSAxOSkNCnRleHQoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwNCiAgICAgbGFiZWxzID0gcGFzdGUoIlRocmVzaG9sZCA9Iiwgcm91bmQoYmVzdF9jb29yZHNbInRocmVzaG9sZCJdLCAyKSksIHBvcyA9IDQpDQpgYGANCg0KYGBge3J9DQojbG9vayBhdC9kaXNjb3Zlci9jcmVhdGUgbW9yZSBtZWFuaW5nZnVsIHRocmVzaG9sZHMgZm9yIHN0cmVuZ3RoIG1ldHJpY3MgcmVsYXRpbmcgdG8gTEIgaW5qdXJ5IHJpc2ssIHRoZW4gdGVzdCBjb25maXJtIHRocmVzaG9sZCBpcyB2YWx1YWJsZSArIGludGVycHJldCAgIA0KYWxsX25vcmRpY19pbmNpZGVudCA8LSAgYWxsX25vcmRpY19pbmNpZGVudCAlPiUNCiAgbXV0YXRlKGFib3ZlX3RocmVzaG9sZD1pZmVsc2UoTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4+PSAzMDEuNDYsIDEsMCkpI2FkZCBuZXdmb3VuZCB0aHJlc2hvbGQgDQojRG9lcyBiZWluZyBhYm92ZSB0aGUgdGhyZXNob2xkIHJlbGF0ZSB0byBsb3dlciBib2R5IGluanVyeSByaXNrPw0KbW9kZWwgPC0gZ2xtKExCLkluanVyeX4gYWJvdmVfdGhyZXNob2xkLGRhdGE9YWxsX25vcmRpY19pbmNpZGVudCwgZmFtaWx5PSJiaW5vbWlhbCIpDQpzdW1tYXJ5KG1vZGVsKQ0Kb2Rkcy5yYXRpbz1leHAoLTAuMTg3ODkpDQooMS1vZGRzLnJhdGlvKSoxMDANCg0KI0dSQVBISUNTDQojZGVuc2l0eSBwbG90DQpnZ3Bsb3QoYWxsX25vcmRpY19pbmNpZGVudCwgYWVzKHggPSBNYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbiwgZmlsbCA9IExCLkluanVyeSkpICsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC40KSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDMwMS40NiwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIiwgc2l6ZSA9IDEpICsNCiAgbGFicyh0aXRsZSA9ICJEZW5zaXR5IFBsb3Q6IE1heGltdW0gTm9yZGljIEJpbGF0ZXJhbCBNZWFuIGJ5IEluanVyeSBTdGF0dXMiLA0KICAgICAgIHggPSAiTWF4aW11bSBOb3JkaWMgQmlsYXRlcmFsIE1lYW4iLA0KICAgICAgIHkgPSAiRGVuc2l0eSIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiMCIgPSAiIzAwMDAwMCIsICIxIiA9ICIjQ0ZCODdDIiksDQogICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiTG93ZXIgQm9keSBJbmp1cnkiLCBsYWJlbHMgPSBjKCJObyIsICJZZXMiKSkgIysNCiAgI3NjYWxlX3hfY29udGludW91cyhsaW1pdHMgPWMoMCwzNSkpDQojYm94cGxvdA0KZ2dwbG90KGFsbF9ub3JkaWNfaW5jaWRlbnQsIGFlcyh4ID0gTEIuSW5qdXJ5LCB5ID0gTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4sIGZpbGwgPSBMQi5Jbmp1cnkpKSArDQogIGdlb21fYm94cGxvdChhbHBoYSA9IDAuNykgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAzMDEuNDYsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIpICsNCiAgbGFicyh0aXRsZSA9ICJCb3hwbG90OiBNYXhpbXVtIE5vcmRpYyBCaWxhdGVyYWwgTWVhbiBieSBJbmp1cnkgU3RhdHVzIiwNCiAgICAgICB4ID0gIkxvd2VyIEJvZHkgSW5qdXJ5IiwgeSA9ICJNYXhpbXVtIE5vcmRpYyBCaWxhdGVyYWwgTWVhbiIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiMCIgPSAiIzAwMDAwMCIsICIxIiA9IiNDRkI4N0MiKSwNCiAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJMQiBJbmp1cnkiLCBsYWJlbHMgPSBjKCJObyIsICJZZXMiKSkjICsNCiAgI3NjYWxlX3lfY29udGludW91cyhsaW1pdHMgPWMoMCwzKSkNCg0KI2NvdW50IGRpc3RyaWJ1dGlvbg0KaW5qdXJ5X2NvdW50cyA8LSBhbGxfbm9yZGljX2luY2lkZW50ICU+JQ0KICBtdXRhdGUoDQogICAgVGhyZXNob2xkID0gaWZlbHNlKGFib3ZlX3RocmVzaG9sZCA9PSAxLCAiQWJvdmUiLCAiQmVsb3ciKSwNCiAgICBJbmp1cnkgPSBpZmVsc2UoTEIuSW5qdXJ5ID09IDEsICJZZXMiLCAiTm8iKQ0KICApICU+JQ0KICBjb3VudChUaHJlc2hvbGQsIEluanVyeSkNCmdncGxvdChpbmp1cnlfY291bnRzLCBhZXMoeCA9IFRocmVzaG9sZCwgeSA9IG4sIGZpbGwgPSBJbmp1cnkpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJzdGFjayIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIlllcyI9JyNDRkI4N0MnLCJObyI9JyMwMDAwMDAnKSkrDQogIGxhYnMoDQogICAgdGl0bGUgPSAiTG93ZXIgQm9keSBJbmp1cnkgQ291bnQgQWJvdmUgdnMgQmVsb3cgdGhlIE1heGltdW0gTm9yZGljIEJpbGF0ZXJhbCBNZWFuIFRocmVzaG9sZCIsDQogICAgeCA9ICJNYXhpbXVtIE5vcmRpYyBCaWxhdGVyYWwgTWVhbiBUaHJlc2hvbGQiLA0KICAgIHkgPSAiQ291bnQiLA0KICAgIGZpbGwgPSAiTG93ZXIgQm9keSBJbmp1cnkiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KI3Byb3BvcnRpb25zIGRpc3RyaWJ1dGlvbg0KdGhyZXNob2xkX3N1bW1hcnkgPC0gYWxsX25vcmRpY19pbmNpZGVudCAlPiUNCiAgZ3JvdXBfYnkoYWJvdmVfdGhyZXNob2xkLCBMQi5Jbmp1cnkpICU+JQ0KICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQ0KICBtdXRhdGUocHJvcCA9IGNvdW50IC8gc3VtKGNvdW50KSkNCg0KZ2dwbG90KHRocmVzaG9sZF9zdW1tYXJ5LCBhZXMoeCA9IGZhY3RvcihhYm92ZV90aHJlc2hvbGQpLCB5ID0gcHJvcCwgZmlsbCA9IGZhY3RvcihMQi5Jbmp1cnkpKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZmlsbCIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiMCIgPSAiIzAwMDAwMCIsICIxIiA9ICIjQ0ZCODdDIiksDQogICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiTG93ZXIgQm9keSBJbmp1cnkiLCBsYWJlbHMgPSBjKCJObyIsICJZZXMiKSkgKw0KICBsYWJzKHggPSAiTWF4aW11bSBOb3JkaWMgQmlsYXRlcmFsIE1lYW4gVGhyZXNob2xkIiwgeSA9ICJQcm9wb3J0aW9uIiwNCiAgICAgICB0aXRsZSA9ICJMb3dlciBCb2R5IEluanVyeSBQcm9wb3J0aW9ucyBBYm92ZSB2cyBCZWxvdyB0aGUgTWF4aW11bSBOb3JkaWMgQmlsYXRlcmFsIE1lYW4gVGhyZXNob2xkIikgKw0KICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoIjAiID0gIkJlbG93IiwgIjEiID0gIkFib3ZlIikpDQpgYGANCg0KYGBge3J9DQphbGxfbm9yZGljX2luY2lkZW50JExCLkluanVyeSA8LSBhcy5mYWN0b3IoYWxsX25vcmRpY19pbmNpZGVudCRMQi5Jbmp1cnkpDQoNCmNwIDwtIGN1dHBvaW50cihhbGxfbm9yZGljX2luY2lkZW50LCBJbXB1bHNlLCBMQi5Jbmp1cnksIG1ldGhvZD1tYXhpbWl6ZV9tZXRyaWMsIG1ldHJpYz15b3VkZW4pDQpwbG90KGNwKQ0Kc3VtbWFyeShjcCkNCmBgYA0KYGBge3J9DQojUk9DIG9iamVjdA0Kcm9jX29iaiA8LSByb2MocmVzcG9uc2UgPSBhbGxfbm9yZGljX2luY2lkZW50JExCLkluanVyeSwNCiAgICAgICAgICAgICAgIHByZWRpY3RvciA9IGFsbF9ub3JkaWNfaW5jaWRlbnQkSW1wdWxzZSwgI3Bvd2VyDQogICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiPiIpICAjIHVzZSAiPCIgaWYgaGlnaGVyIHZhbHVlcz0gaGlnaCByaXNrIHByZWRpY3QgJ05vJw0KICAgICAgICAgICAgICAgIyBpZiA+IHJlbC4gY29uLiBwb3dlciB0aGVuIGxvd2VyIHJpc2sNCiNwbG90IGN1cnZlDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIC0gSW1wdWxzZSIpDQphdWNfdmFsdWUgPC0gYXVjKHJvY19vYmopDQpwcmludChhdWNfdmFsdWUpDQpiZXN0X2Nvb3JkcyA8LSBjb29yZHMocm9jX29iaiwgImJlc3QiLCByZXQgPSBjKCJ0aHJlc2hvbGQiLCAic2Vuc2l0aXZpdHkiLCAic3BlY2lmaWNpdHkiKSwgYmVzdC5tZXRob2QgPSAieW91ZGVuIikNCmJlc3RfY29vcmRzDQoNCiNwbG90ICsgdGhyZXNob2xkDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIHdpdGggT3B0aW1hbCBUaHJlc2hvbGQiKQ0KYWJsaW5lKGEgPSAwLCBiID0gMSwgbHR5ID0gMiwgY29sID0gImdyYXkiKQ0KcG9pbnRzKDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sIGNvbCA9ICcjQ0ZCODdDJywgcGNoID0gMTkpDQp0ZXh0KDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sDQogICAgIGxhYmVscyA9IHBhc3RlKCJUaHJlc2hvbGQgPSIsIHJvdW5kKGJlc3RfY29vcmRzWyJ0aHJlc2hvbGQiXSwgMikpLCBwb3MgPSA0KQ0KYGBgDQoNCmBgYHtyfQ0KI2xvb2sgYXQvZGlzY292ZXIvY3JlYXRlIG1vcmUgbWVhbmluZ2Z1bCB0aHJlc2hvbGRzIGZvciBzdHJlbmd0aCBtZXRyaWNzIHJlbGF0aW5nIHRvIExCIGluanVyeSByaXNrLCB0aGVuIHRlc3QgY29uZmlybSB0aHJlc2hvbGQgaXMgdmFsdWFibGUgKyBpbnRlcnByZXQgICANCmFsbF9ub3JkaWNfaW5jaWRlbnQgPC0gIGFsbF9ub3JkaWNfaW5jaWRlbnQgJT4lDQogIG11dGF0ZShhYm92ZV90aHJlc2hvbGQ9aWZlbHNlKEltcHVsc2U+PSA1OTM5LjAzNSwgMSwwKSkjYWRkIG5ld2ZvdW5kIHRocmVzaG9sZCANCiNEb2VzIGJlaW5nIGFib3ZlIHRoZSB0aHJlc2hvbGQgcmVsYXRlIHRvIGxvd2VyIGJvZHkgaW5qdXJ5IHJpc2s/DQptb2RlbCA8LSBnbG0oTEIuSW5qdXJ5fiBhYm92ZV90aHJlc2hvbGQsZGF0YT1hbGxfbm9yZGljX2luY2lkZW50LCBmYW1pbHk9ImJpbm9taWFsIikNCnN1bW1hcnkobW9kZWwpDQpvZGRzLnJhdGlvPWV4cCgtMC40ODA0NCkNCigxLW9kZHMucmF0aW8pKjEwMA0KYGBgDQoNCmBgYHtyfQ0KYWxsX25vcmRpY19pbmNpZGVudCRMQi5Jbmp1cnkgPC0gYXMuZmFjdG9yKGFsbF9ub3JkaWNfaW5jaWRlbnQkTEIuSW5qdXJ5KQ0KDQpjcCA8LSBjdXRwb2ludHIoYWxsX25vcmRpY19pbmNpZGVudCwgTm9yZGljLk1BWC5JbWJhbGFuY2UsIExCLkluanVyeSwgbWV0aG9kPW1heGltaXplX21ldHJpYywgbWV0cmljPXlvdWRlbikNCnBsb3QoY3ApDQpzdW1tYXJ5KGNwKQ0KYGBgDQpgYGB7cn0NCiNST0Mgb2JqZWN0DQpyb2Nfb2JqIDwtIHJvYyhyZXNwb25zZSA9IGFsbF9ub3JkaWNfaW5jaWRlbnQkTEIuSW5qdXJ5LA0KICAgICAgICAgICAgICAgcHJlZGljdG9yID0gYWxsX25vcmRpY19pbmNpZGVudCROb3JkaWMuTUFYLkltYmFsYW5jZSwgI3Bvd2VyDQogICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiPiIpICAjIHVzZSAiPCIgaWYgaGlnaGVyIHZhbHVlcz0gaGlnaCByaXNrIHByZWRpY3QgJ05vJw0KICAgICAgICAgICAgICAgIyBpZiA+IHJlbC4gY29uLiBwb3dlciB0aGVuIGxvd2VyIHJpc2sNCiNwbG90IGN1cnZlDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIC0gSW1wdWxzZSIpDQphdWNfdmFsdWUgPC0gYXVjKHJvY19vYmopDQpwcmludChhdWNfdmFsdWUpDQpiZXN0X2Nvb3JkcyA8LSBjb29yZHMocm9jX29iaiwgImJlc3QiLCByZXQgPSBjKCJ0aHJlc2hvbGQiLCAic2Vuc2l0aXZpdHkiLCAic3BlY2lmaWNpdHkiKSwgYmVzdC5tZXRob2QgPSAieW91ZGVuIikNCmJlc3RfY29vcmRzDQoNCiNwbG90ICsgdGhyZXNob2xkDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIHdpdGggT3B0aW1hbCBUaHJlc2hvbGQiKQ0KYWJsaW5lKGEgPSAwLCBiID0gMSwgbHR5ID0gMiwgY29sID0gImdyYXkiKQ0KcG9pbnRzKDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sIGNvbCA9ICcjQ0ZCODdDJywgcGNoID0gMTkpDQp0ZXh0KDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sDQogICAgIGxhYmVscyA9IHBhc3RlKCJUaHJlc2hvbGQgPSIsIHJvdW5kKGJlc3RfY29vcmRzWyJ0aHJlc2hvbGQiXSwgMikpLCBwb3MgPSA0KQ0KYGBgDQoNCmBgYHtyfQ0KI2xvb2sgYXQvZGlzY292ZXIvY3JlYXRlIG1vcmUgbWVhbmluZ2Z1bCB0aHJlc2hvbGRzIGZvciBzdHJlbmd0aCBtZXRyaWNzIHJlbGF0aW5nIHRvIExCIGluanVyeSByaXNrLCB0aGVuIHRlc3QgY29uZmlybSB0aHJlc2hvbGQgaXMgdmFsdWFibGUgKyBpbnRlcnByZXQgICANCmFsbF9ub3JkaWNfaW5jaWRlbnQgPC0gIGFsbF9ub3JkaWNfaW5jaWRlbnQgJT4lDQogIG11dGF0ZShhYm92ZV90aHJlc2hvbGQ9aWZlbHNlKE5vcmRpYy5NQVguSW1iYWxhbmNlPj0gMTAuNyAsIDEsMCkpI2FkZCBuZXdmb3VuZCB0aHJlc2hvbGQgDQojRG9lcyBiZWluZyBhYm92ZSB0aGUgdGhyZXNob2xkIHJlbGF0ZSB0byBsb3dlciBib2R5IGluanVyeSByaXNrPw0KbW9kZWwgPC0gZ2xtKExCLkluanVyeX4gYWJvdmVfdGhyZXNob2xkLGRhdGE9YWxsX25vcmRpY19pbmNpZGVudCwgZmFtaWx5PSJiaW5vbWlhbCIpDQpzdW1tYXJ5KG1vZGVsKQ0KYGBgDQoNCg0KI0NNSg0KMS4gUmVsYXRpdmUuQ29uY2VudHJpYy5Qb3dlci5CaWxhdGVyYWwNCmBgYHtyfQ0KI3dheSAxIHRvIGZpbmQgdGhyZXNob2xkDQphbGxfQ01KX2luY2lkZW50JExCLkluanVyeSA8LSBhcy5mYWN0b3IoYWxsX0NNSl9pbmNpZGVudCRMQi5Jbmp1cnkpDQoNCiNFcnJvcjogIlJlbGF0aXZlLkNvbmNlbnRyaWMuUG93ZXIuQmlsYXRlcmFsIiwgOm1ldGhvZCBzaG91bGQgYmUgYSBmdW5jdGlvbg0KY3AgPC0gY3V0cG9pbnRyKGFsbF9DTUpfaW5jaWRlbnQsIFJlbGF0aXZlLkNvbmNlbnRyaWMuUG93ZXIuQmlsYXRlcmFsLCBMQi5Jbmp1cnksIG1ldGhvZD1tYXhpbWl6ZV9tZXRyaWMsIG1ldHJpYz15b3VkZW4pDQpwbG90KGNwKQ0Kc3VtbWFyeShjcCkNCmBgYA0KRm9yIFJlbGF0aXZlIENvbmNlbnRyaWMgUG93ZXIgQmlsYXRlcmFsIHRoZSBvcHRpbWFsIGN1dHBvaW50IGlzIDEwLjMgd2l0aCBhIEFVQyBvZiAwLjUwMjgsIHNlbnNpdGl2aXR5IG9mIDAuNzIxIGFuZCBzcGVjaWZpY2l0eSBvZiAwLjMxOTEuDQoNCmBgYHtyfQ0KI3dheSAyIHRvIGZpbmQgdGhyZXNob2xkIA0KI1JPQyBvYmplY3QNCnJvY19vYmogPC0gcm9jKHJlc3BvbnNlID0gYWxsX0NNSl9pbmNpZGVudCRMQi5Jbmp1cnksDQogICAgICAgICAgICAgICBwcmVkaWN0b3IgPSBhbGxfQ01KX2luY2lkZW50JFJlbGF0aXZlLkNvbmNlbnRyaWMuUG93ZXIuQmlsYXRlcmFsLCAjcG93ZXINCiAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICI+IikgICMgdXNlICI8IiBpZiBoaWdoZXIgdmFsdWVzPSBoaWdoIHJpc2sgcHJlZGljdCAnTm8nDQogICAgICAgICAgICAgICAjIGlmID4gcmVsLiBjb24uIHBvd2VyIHRoZW4gbG93ZXIgcmlzaw0KI3Bsb3QgY3VydmUNCnBsb3Qocm9jX29iaiwgbWFpbiA9ICJST0MgQ3VydmUgLSBSZWxhdGl2ZSBDb25jZW50cmljIEJpbGF0ZXJhbCBQb3dlciIpDQphdWNfdmFsdWUgPC0gYXVjKHJvY19vYmopDQpwcmludChhdWNfdmFsdWUpDQpiZXN0X2Nvb3JkcyA8LSBjb29yZHMocm9jX29iaiwgImJlc3QiLCByZXQgPSBjKCJ0aHJlc2hvbGQiLCAic2Vuc2l0aXZpdHkiLCAic3BlY2lmaWNpdHkiKSwgYmVzdC5tZXRob2QgPSAieW91ZGVuIikNCmJlc3RfY29vcmRzDQoNCiNwbG90ICsgdGhyZXNob2xkDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIHdpdGggT3B0aW1hbCBUaHJlc2hvbGQiKQ0KYWJsaW5lKGEgPSAwLCBiID0gMSwgbHR5ID0gMiwgY29sID0gImdyYXkiKQ0KcG9pbnRzKDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sIGNvbCA9ICcjQ0ZCODdDJywgcGNoID0gMTkpDQp0ZXh0KDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sDQogICAgIGxhYmVscyA9IHBhc3RlKCJUaHJlc2hvbGQgPSIsIHJvdW5kKGJlc3RfY29vcmRzWyJ0aHJlc2hvbGQiXSwgMikpLCBwb3MgPSA0KQ0KYGBgDQpGb3IgUmVsYXRpdmUgQ29uY2VudHJpYyBQb3dlciBCaWxhdGVyYWwgdGhlIG9wdGltYWwgdGhyZXNob2xkIHdhcyAxMC44NSwgd2l0aCBhbiBBVUMgb2YgMC40OTcyLCBzZW5zaXRpdml0eSAwLjU2MjU3MjYsIGFuZCBzcGVjaWZpY2l0eSAwLjQ3MDc4NjUuDQoNCmBgYHtyfQ0KI2xvb2sgYXQvZGlzY292ZXIvY3JlYXRlIG1vcmUgbWVhbmluZ2Z1bCB0aHJlc2hvbGRzIGZvciBzdHJlbmd0aCBtZXRyaWNzIHJlbGF0aW5nIHRvIExCIGluanVyeSByaXNrLCB0aGVuIHRlc3QgY29uZmlybSB0aHJlc2hvbGQgaXMgdmFsdWFibGUgKyBpbnRlcnByZXQNCmFsbF9DTUpfaW5jaWRlbnQgPC0gIGFsbF9DTUpfaW5jaWRlbnQgJT4lDQogIG11dGF0ZShhYm92ZV90aHJlc2hvbGQ9aWZlbHNlKFJlbGF0aXZlLkNvbmNlbnRyaWMuUG93ZXIuQmlsYXRlcmFsPj0gMTAuMywgMSwwKSkjYWRkIG5ld2ZvdW5kIHRocmVzaG9sZCANCg0KI0RvZXMgYmVpbmcgYWJvdmUgdGhlIHRocmVzaG9sZCByZWxhdGUgdG8gbG93ZXIgYm9keSBpbmp1cnkgcmlzaz8NCm1vZGVsIDwtIGdsbShMQi5Jbmp1cnl+IGFib3ZlX3RocmVzaG9sZCxkYXRhPWFsbF9DTUpfaW5jaWRlbnQsIGZhbWlseT0iYmlub21pYWwiKQ0Kc3VtbWFyeShtb2RlbCkNCmBgYA0KDQoyLiBFY2NlbnRyaWMuQ29uY2VudHJpYy5NZWFuLkZvcmNlLlJhdGlvDQpgYGB7cn0NCmFsbF9DTUpfaW5jaWRlbnQkTEIuSW5qdXJ5IDwtIGFzLmZhY3RvcihhbGxfQ01KX2luY2lkZW50JExCLkluanVyeSkNCg0KY3AgPC0gY3V0cG9pbnRyKGFsbF9DTUpfaW5jaWRlbnQsIEVjY2VudHJpYy5Db25jZW50cmljLk1lYW4uRm9yY2UuUmF0aW8gLCBMQi5Jbmp1cnksIG1ldGhvZD1tYXhpbWl6ZV9tZXRyaWMsIG1ldHJpYz15b3VkZW4pDQpwbG90KGNwKQ0Kc3VtbWFyeShjcCkNCmBgYA0KRm9yIEVjY2VudHJpYyBDb25jZW50cmljIE1lYW4gRm9yY2UgUmF0aW8gdGhlIG9wdGltYWwgY3V0cG9pbnQgaXMgNTMuNTAyNSB3aXRoIGEgQVVDIG9mIDAuNDkzOCwgc2Vuc2l0aXZpdHkgb2YgMC40OTM5OCBhbmQgc3BlY2lmaWNpdHkgb2YgMC42MjAyLg0KDQpgYGB7cn0NCiNST0Mgb2JqZWN0DQpyb2Nfb2JqIDwtIHJvYyhyZXNwb25zZSA9IGFsbF9DTUpfaW5jaWRlbnQkTEIuSW5qdXJ5LA0KICAgICAgICAgICAgICAgcHJlZGljdG9yID0gYWxsX0NNSl9pbmNpZGVudCRFY2NlbnRyaWMuQ29uY2VudHJpYy5NZWFuLkZvcmNlLlJhdGlvICwgI3Bvd2VyDQogICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiPiIpICAjIHVzZSAiPCIgaWYgaGlnaGVyIHZhbHVlcz0gaGlnaCByaXNrIHByZWRpY3QgJ05vJw0KICAgICAgICAgICAgICAgIyBpZiA+IHJlbC4gY29uLiBwb3dlciB0aGVuIGxvd2VyIHJpc2sNCiNwbG90IGN1cnZlDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIC0gRWNjZW50cmljIENvbmNlbnRyaWMgTWVhbiBGb3JjZSBSYXRpbyIpDQphdWNfdmFsdWUgPC0gYXVjKHJvY19vYmopDQpwcmludChhdWNfdmFsdWUpDQpiZXN0X2Nvb3JkcyA8LSBjb29yZHMocm9jX29iaiwgImJlc3QiLCByZXQgPSBjKCJ0aHJlc2hvbGQiLCAic2Vuc2l0aXZpdHkiLCAic3BlY2lmaWNpdHkiKSwgYmVzdC5tZXRob2QgPSAieW91ZGVuIikNCmJlc3RfY29vcmRzDQoNCiNwbG90ICsgdGhyZXNob2xkDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIHdpdGggT3B0aW1hbCBUaHJlc2hvbGQiKQ0KYWJsaW5lKGEgPSAwLCBiID0gMSwgbHR5ID0gMiwgY29sID0gImdyYXkiKQ0KcG9pbnRzKDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sIGNvbCA9ICcjQ0ZCODdDJywgcGNoID0gMTkpDQp0ZXh0KDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sDQogICAgIGxhYmVscyA9IHBhc3RlKCJUaHJlc2hvbGQgPSIsIHJvdW5kKGJlc3RfY29vcmRzWyJ0aHJlc2hvbGQiXSwgMikpLCBwb3MgPSA0KQ0KYGBgDQpGb3IgRWNjZW50cmljIENvbmNlbnRyaWMgTWVhbiBGb3JjZSBSYXRpbyB0aGUgb3B0aW1hbCB0aHJlc2hvbGQgaXMgNDcuNzE0NSB3aXRoIGEgQVVDIG9mIDAuNTA2Miwgc2Vuc2l0aXZpdHkgb2YgMC4xNjY2MDIxIGFuZCBzcGVjaWZpY2l0eSBvZiAwLjkxNTczMDMuDQoNCmBgYHtyfQ0KI2xvb2sgYXQvZGlzY292ZXIvY3JlYXRlIG1vcmUgbWVhbmluZ2Z1bCB0aHJlc2hvbGRzIGZvciBzdHJlbmd0aCBtZXRyaWNzIHJlbGF0aW5nIHRvIExCIGluanVyeSByaXNrLCB0aGVuIHRlc3QgY29uZmlybSB0aHJlc2hvbGQgaXMgdmFsdWFibGUgKyBpbnRlcnByZXQNCmFsbF9DTUpfaW5jaWRlbnQgPC0gIGFsbF9DTUpfaW5jaWRlbnQgJT4lDQogIG11dGF0ZShhYm92ZV90aHJlc2hvbGQ9aWZlbHNlKEVjY2VudHJpYy5Db25jZW50cmljLk1lYW4uRm9yY2UuUmF0aW8+PSA0Ny43MTQ1LCAxLDApKSNhZGQgbmV3Zm91bmQgdGhyZXNob2xkDQoNCiNEb2VzIGJlaW5nIGFib3ZlIHRoZSB0aHJlc2hvbGQgcmVsYXRlIHRvIGxvd2VyIGJvZHkgaW5qdXJ5IHJpc2s/DQptb2RlbCA8LSBnbG0oTEIuSW5qdXJ5fiBhYm92ZV90aHJlc2hvbGQsZGF0YT1hbGxfQ01KX2luY2lkZW50LCBmYW1pbHk9ImJpbm9taWFsIikNCnN1bW1hcnkobW9kZWwpDQpgYGANCg0KMy4gTWF4aW11bSBKdW1wIEhlaWdodA0KYGBge3J9DQphbGxfQ01KX2luY2lkZW50JExCLkluanVyeSA8LSBhcy5mYWN0b3IoYWxsX0NNSl9pbmNpZGVudCRMQi5Jbmp1cnkpDQoNCmNwIDwtIGN1dHBvaW50cihhbGxfQ01KX2luY2lkZW50LCBNYXguSnVtcC5IZWlnaHQuLmNtLiAsIExCLkluanVyeSwgbWV0aG9kPW1heGltaXplX21ldHJpYywgbWV0cmljPXlvdWRlbikNCnBsb3QoY3ApDQpzdW1tYXJ5KGNwKQ0KYGBgDQpGb3IgTWF4aW11bSBKdW1wIEhlaWdodCB0aGUgb3B0aW1hbCBjdXRwb2ludCBpcyA0MS4zNzkgd2l0aCBhIEFVQyBvZiAwLjUwNjMsIHNlbnNpdGl2aXR5IG9mIDAuMDk1NyBhbmQgc3BlY2lmaWNpdHkgb2YgMDk2MTguDQoNCmBgYHtyfQ0KI1JPQyBvYmplY3QNCnJvY19vYmogPC0gcm9jKHJlc3BvbnNlID0gYWxsX0NNSl9pbmNpZGVudCRMQi5Jbmp1cnksDQogICAgICAgICAgICAgICBwcmVkaWN0b3IgPSBhbGxfQ01KX2luY2lkZW50JE1heC5KdW1wLkhlaWdodC4uY20uICwgI3Bvd2VyDQogICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiPiIpICAjIHVzZSAiPCIgaWYgaGlnaGVyIHZhbHVlcz0gaGlnaCByaXNrIHByZWRpY3QgJ05vJw0KICAgICAgICAgICAgICAgIyBpZiA+IHJlbC4gY29uLiBwb3dlciB0aGVuIGxvd2VyIHJpc2sNCiNwbG90IGN1cnZlDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIC0gTWF4aW11bSBKdW1wIEhlaWdodCIpDQphdWNfdmFsdWUgPC0gYXVjKHJvY19vYmopDQpwcmludChhdWNfdmFsdWUpDQpiZXN0X2Nvb3JkcyA8LSBjb29yZHMocm9jX29iaiwgImJlc3QiLCByZXQgPSBjKCJ0aHJlc2hvbGQiLCAic2Vuc2l0aXZpdHkiLCAic3BlY2lmaWNpdHkiKSwgYmVzdC5tZXRob2QgPSAieW91ZGVuIikNCmJlc3RfY29vcmRzDQoNCiNwbG90ICsgdGhyZXNob2xkDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIHdpdGggT3B0aW1hbCBUaHJlc2hvbGQiKQ0KYWJsaW5lKGEgPSAwLCBiID0gMSwgbHR5ID0gMiwgY29sID0gImdyYXkiKQ0KcG9pbnRzKDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sIGNvbCA9ICcjQ0ZCODdDJywgcGNoID0gMTkpDQp0ZXh0KDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sDQogICAgIGxhYmVscyA9IHBhc3RlKCJUaHJlc2hvbGQgPSIsIHJvdW5kKGJlc3RfY29vcmRzWyJ0aHJlc2hvbGQiXSwgMikpLCBwb3MgPSA0KQ0KYGBgDQpGb3IgTWF4aW11bSBKdW1wIEhlaWdodCB0aGUgb3B0aW1hbCB0aHJlc2hvbGQgaXMgMjQuNiB3aXRoIGEgQVVDIG9mIDAuNDkzNywgc2Vuc2l0aXZpdHkgb2YgMC4wNzI0NTI1NCBhbmQgc3BlY2lmaWNpdHkgb2YgMC45NTk1NTA2Lg0KDQpgYGB7cn0NCiNsb29rIGF0L2Rpc2NvdmVyL2NyZWF0ZSBtb3JlIG1lYW5pbmdmdWwgdGhyZXNob2xkcyBmb3Igc3RyZW5ndGggbWV0cmljcyByZWxhdGluZyB0byBMQiBpbmp1cnkgcmlzaywgdGhlbiB0ZXN0IGNvbmZpcm0gdGhyZXNob2xkIGlzIHZhbHVhYmxlICsgaW50ZXJwcmV0DQphbGxfQ01KX2luY2lkZW50IDwtICBhbGxfQ01KX2luY2lkZW50ICU+JQ0KICBtdXRhdGUoYWJvdmVfdGhyZXNob2xkPWlmZWxzZShNYXguSnVtcC5IZWlnaHQuLmNtLj49IDQxLjM3OSwgMSwwKSkjYWRkIG5ld2ZvdW5kIHRocmVzaG9sZA0KDQojRG9lcyBiZWluZyBhYm92ZSB0aGUgdGhyZXNob2xkIHJlbGF0ZSB0byBsb3dlciBib2R5IGluanVyeSByaXNrPw0KbW9kZWwgPC0gZ2xtKExCLkluanVyeX4gYWJvdmVfdGhyZXNob2xkLGRhdGE9YWxsX0NNSl9pbmNpZGVudCwgZmFtaWx5PSJiaW5vbWlhbCIpDQpzdW1tYXJ5KG1vZGVsKQ0KYGBgDQoNCjQuIE1heGltdW0gQ29uY2VudHJpYyBSRkQNCmBgYHtyfQ0KYWxsX0NNSl9pbmNpZGVudCRMQi5Jbmp1cnkgPC0gYXMuZmFjdG9yKGFsbF9DTUpfaW5jaWRlbnQkTEIuSW5qdXJ5KQ0KDQpjcCA8LSBjdXRwb2ludHIoYWxsX0NNSl9pbmNpZGVudCwgTWF4LkNvbmNlbnRyaWMuUlBELi5OLnMuICwgTEIuSW5qdXJ5LCBtZXRob2Q9bWF4aW1pemVfbWV0cmljLCBtZXRyaWM9eW91ZGVuKQ0KcGxvdChjcCkNCnN1bW1hcnkoY3ApDQpgYGANCkZvciBNYXhpbXVtIENvbmNlbnRyaWMgUkZEIHRoZSBvcHRpbWFsIGN1dHBvaW50IGlzIDE1Nzg0LjM0IHdpdGggYSBBVUMgb2YgMC41MjcsIHNlbnNpdGl2aXR5IG9mIDAuNjAzNCBhbmQgc3BlY2lmaWNpdHkgb2YgMC40OTYzLg0KDQpgYGB7cn0NCiNST0Mgb2JqZWN0DQpyb2Nfb2JqIDwtIHJvYyhyZXNwb25zZSA9IGFsbF9DTUpfaW5jaWRlbnQkTEIuSW5qdXJ5LA0KICAgICAgICAgICAgICAgcHJlZGljdG9yID0gYWxsX0NNSl9pbmNpZGVudCRNYXguQ29uY2VudHJpYy5SUEQuLk4ucy4gLCAjcG93ZXINCiAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICI+IikgICMgdXNlICI8IiBpZiBoaWdoZXIgdmFsdWVzPSBoaWdoIHJpc2sgcHJlZGljdCAnTm8nDQogICAgICAgICAgICAgICAjIGlmID4gcmVsLiBjb24uIHBvd2VyIHRoZW4gbG93ZXIgcmlzaw0KI3Bsb3QgY3VydmUNCnBsb3Qocm9jX29iaiwgbWFpbiA9ICJST0MgQ3VydmUgLSBNYXhpbXVtIENvbmNlbnRyaWMgUkZEIikNCmF1Y192YWx1ZSA8LSBhdWMocm9jX29iaikNCnByaW50KGF1Y192YWx1ZSkNCmJlc3RfY29vcmRzIDwtIGNvb3Jkcyhyb2Nfb2JqLCAiYmVzdCIsIHJldCA9IGMoInRocmVzaG9sZCIsICJzZW5zaXRpdml0eSIsICJzcGVjaWZpY2l0eSIpLCBiZXN0Lm1ldGhvZCA9ICJ5b3VkZW4iKQ0KYmVzdF9jb29yZHMNCg0KI3Bsb3QgKyB0aHJlc2hvbGQNCnBsb3Qocm9jX29iaiwgbWFpbiA9ICJST0MgQ3VydmUgd2l0aCBPcHRpbWFsIFRocmVzaG9sZCIpDQphYmxpbmUoYSA9IDAsIGIgPSAxLCBsdHkgPSAyLCBjb2wgPSAiZ3JheSIpDQpwb2ludHMoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwgY29sID0gJyNDRkI4N0MnLCBwY2ggPSAxOSkNCnRleHQoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwNCiAgICAgbGFiZWxzID0gcGFzdGUoIlRocmVzaG9sZCA9Iiwgcm91bmQoYmVzdF9jb29yZHNbInRocmVzaG9sZCJdLCAyKSksIHBvcyA9IDQpDQpgYGANCkZvciBNYXhpbXVtIENvbmNlbnRyaWMgUkZEIHRoZSBvcHRpbWFsIHRocmVzaG9sZCBpcyAxNTc4MC42NiB3aXRoIGEgQVVDIG9mIDAuNTI3LCBzZW5zaXRpdml0eSBvZiAwLjQ5NjMxMyBhbmQgc3BlY2lmaWNpdHkgb2YgMC42MDMzNzA4Lg0KDQpgYGB7cn0NCiNsb29rIGF0L2Rpc2NvdmVyL2NyZWF0ZSBtb3JlIG1lYW5pbmdmdWwgdGhyZXNob2xkcyBmb3Igc3RyZW5ndGggbWV0cmljcyByZWxhdGluZyB0byBMQiBpbmp1cnkgcmlzaywgdGhlbiB0ZXN0IGNvbmZpcm0gdGhyZXNob2xkIGlzIHZhbHVhYmxlICsgaW50ZXJwcmV0DQphbGxfQ01KX2luY2lkZW50IDwtICBhbGxfQ01KX2luY2lkZW50ICU+JQ0KICBtdXRhdGUoYWJvdmVfdGhyZXNob2xkPWlmZWxzZShNYXguQ29uY2VudHJpYy5SUEQuLk4ucy4+PSAxNTc4NC4zNCwgMSwwKSkjYWRkIG5ld2ZvdW5kIHRocmVzaG9sZA0KDQojRG9lcyBiZWluZyBhYm92ZSB0aGUgdGhyZXNob2xkIHJlbGF0ZSB0byBsb3dlciBib2R5IGluanVyeSByaXNrPw0KbW9kZWwgPC0gZ2xtKExCLkluanVyeX4gYWJvdmVfdGhyZXNob2xkLGRhdGE9YWxsX0NNSl9pbmNpZGVudCwgZmFtaWx5PSJiaW5vbWlhbCIpDQpzdW1tYXJ5KG1vZGVsKQ0KYGBgDQoNCjUuIEVjY2VudHJpYyBNZWFuIEJyYWtpbmcgRm9yY2UNCmBgYHtyfQ0KYWxsX0NNSl9pbmNpZGVudCRMQi5Jbmp1cnkgPC0gYXMuZmFjdG9yKGFsbF9DTUpfaW5jaWRlbnQkTEIuSW5qdXJ5KQ0KDQpjcCA8LSBjdXRwb2ludHIoYWxsX0NNSl9pbmNpZGVudCwgRWNjZW50cmljLk1lYW4uQnJha2luZy5Gb3JjZS4uTi4gLCBMQi5Jbmp1cnksIG1ldGhvZD1tYXhpbWl6ZV9tZXRyaWMsIG1ldHJpYz15b3VkZW4pDQpwbG90KGNwKQ0Kc3VtbWFyeShjcCkNCmBgYA0KRm9yIEVjY2VudHJpYyBNZWFuIEJyYWtpbmcgRm9yY2UgdGhlIG9wdGltYWwgY3V0cG9pbnQgaXMgNzgzLjUxNyB3aXRoIGEgQVVDIG9mIDAuNTk4OSwgc2Vuc2l0aXZpdHkgb2YgMC43MTQ2IGFuZCBzcGVjaWZpY2l0eSBvZiAwLjQ1NzIuDQoNCmBgYHtyfQ0KI1JPQyBvYmplY3QNCnJvY19vYmogPC0gcm9jKHJlc3BvbnNlID0gYWxsX0NNSl9pbmNpZGVudCRMQi5Jbmp1cnksDQogICAgICAgICAgICAgICBwcmVkaWN0b3IgPSBhbGxfQ01KX2luY2lkZW50JEVjY2VudHJpYy5NZWFuLkJyYWtpbmcuRm9yY2UuLk4uICwgI3Bvd2VyDQogICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiPiIpICAjIHVzZSAiPCIgaWYgaGlnaGVyIHZhbHVlcz0gaGlnaCByaXNrIHByZWRpY3QgJ05vJw0KICAgICAgICAgICAgICAgIyBpZiA+IHJlbC4gY29uLiBwb3dlciB0aGVuIGxvd2VyIHJpc2sNCiNwbG90IGN1cnZlDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIC0gRWNjZW50cmljIE1lYW4gQnJha2luZyBGb3JjZSIpDQphdWNfdmFsdWUgPC0gYXVjKHJvY19vYmopDQpwcmludChhdWNfdmFsdWUpDQpiZXN0X2Nvb3JkcyA8LSBjb29yZHMocm9jX29iaiwgImJlc3QiLCByZXQgPSBjKCJ0aHJlc2hvbGQiLCAic2Vuc2l0aXZpdHkiLCAic3BlY2lmaWNpdHkiKSwgYmVzdC5tZXRob2QgPSAieW91ZGVuIikNCmJlc3RfY29vcmRzDQoNCiNwbG90ICsgdGhyZXNob2xkDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIHdpdGggT3B0aW1hbCBUaHJlc2hvbGQiKQ0KYWJsaW5lKGEgPSAwLCBiID0gMSwgbHR5ID0gMiwgY29sID0gImdyYXkiKQ0KcG9pbnRzKDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sIGNvbCA9ICcjQ0ZCODdDJywgcGNoID0gMTkpDQp0ZXh0KDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sDQogICAgIGxhYmVscyA9IHBhc3RlKCJUaHJlc2hvbGQgPSIsIHJvdW5kKGJlc3RfY29vcmRzWyJ0aHJlc2hvbGQiXSwgMikpLCBwb3MgPSA0KQ0KYGBgDQpGb3IgRWNjZW50cmljIE1lYW4gQnJha2luZyBGb3JjZSB0aGUgb3B0aW1hbCB0aHJlc2hvbGQgaXMgNzgzLjQ5NjMgd2l0aCBhIEFVQyBvZiAwLjU5ODksIHNlbnNpdGl2aXR5IG9mIDAuNDU3MTg3MSBhbmQgc3BlY2lmaWNpdHkgb2YgMC43MTQ2MDY3Lg0KDQpgYGB7cn0NCiNsb29rIGF0L2Rpc2NvdmVyL2NyZWF0ZSBtb3JlIG1lYW5pbmdmdWwgdGhyZXNob2xkcyBmb3Igc3RyZW5ndGggbWV0cmljcyByZWxhdGluZyB0byBMQiBpbmp1cnkgcmlzaywgdGhlbiB0ZXN0IGNvbmZpcm0gdGhyZXNob2xkIGlzIHZhbHVhYmxlICsgaW50ZXJwcmV0DQphbGxfQ01KX2luY2lkZW50IDwtICBhbGxfQ01KX2luY2lkZW50ICU+JQ0KICBtdXRhdGUoYWJvdmVfdGhyZXNob2xkPWlmZWxzZShFY2NlbnRyaWMuTWVhbi5CcmFraW5nLkZvcmNlLi5OLj49IDc4My41MTcsIDEsMCkpI2FkZCBuZXdmb3VuZCB0aHJlc2hvbGQNCg0KI0RvZXMgYmVpbmcgYWJvdmUgdGhlIHRocmVzaG9sZCByZWxhdGUgdG8gbG93ZXIgYm9keSBpbmp1cnkgcmlzaz8NCm1vZGVsIDwtIGdsbShMQi5Jbmp1cnl+IGFib3ZlX3RocmVzaG9sZCxkYXRhPWFsbF9DTUpfaW5jaWRlbnQsIGZhbWlseT0iYmlub21pYWwiKQ0Kc3VtbWFyeShtb2RlbCkNCmBgYA0KDQo2LiBNYXhpbXVtIFZBTEQgUlNJDQpgYGB7cn0NCmFsbF9DTUpfaW5jaWRlbnQkTEIuSW5qdXJ5IDwtIGFzLmZhY3RvcihhbGxfQ01KX2luY2lkZW50JExCLkluanVyeSkNCg0KY3AgPC0gY3V0cG9pbnRyKGFsbF9DTUpfaW5jaWRlbnQsIE1heC5SU0kuTW9kaWZpZWQuVkFMRCAsIExCLkluanVyeSwgbWV0aG9kPW1heGltaXplX21ldHJpYywgbWV0cmljPXlvdWRlbikNCnBsb3QoY3ApDQpzdW1tYXJ5KGNwKQ0KYGBgDQpGb3IgTWF4aW11bSBWQUxEIFJTSSB0aGUgb3B0aW1hbCBjdXRwb2ludCBpcyAwLjQgd2l0aCBhIEFVQyBvZiAwLjUyNjMsIHNlbnNpdGl2aXR5IG9mIDAuNjU2MiBhbmQgc3BlY2lmaWNpdHkgb2YgMC40MDYuDQoNCmBgYHtyfQ0KI1JPQyBvYmplY3QNCnJvY19vYmogPC0gcm9jKHJlc3BvbnNlID0gYWxsX0NNSl9pbmNpZGVudCRMQi5Jbmp1cnksDQogICAgICAgICAgICAgICBwcmVkaWN0b3IgPSBhbGxfQ01KX2luY2lkZW50JE1heC5SU0kuTW9kaWZpZWQuVkFMRCAsICNwb3dlcg0KICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gIj4iKSAgIyB1c2UgIjwiIGlmIGhpZ2hlciB2YWx1ZXM9IGhpZ2ggcmlzayBwcmVkaWN0ICdObycNCiAgICAgICAgICAgICAgICMgaWYgPiByZWwuIGNvbi4gcG93ZXIgdGhlbiBsb3dlciByaXNrDQojcGxvdCBjdXJ2ZQ0KcGxvdChyb2Nfb2JqLCBtYWluID0gIlJPQyBDdXJ2ZSAtIE1heGltdW0gVkFMRCBSU0kiKQ0KYXVjX3ZhbHVlIDwtIGF1Yyhyb2Nfb2JqKQ0KcHJpbnQoYXVjX3ZhbHVlKQ0KYmVzdF9jb29yZHMgPC0gY29vcmRzKHJvY19vYmosICJiZXN0IiwgcmV0ID0gYygidGhyZXNob2xkIiwgInNlbnNpdGl2aXR5IiwgInNwZWNpZmljaXR5IiksIGJlc3QubWV0aG9kID0gInlvdWRlbiIpDQpiZXN0X2Nvb3Jkcw0KDQojcGxvdCArIHRocmVzaG9sZA0KcGxvdChyb2Nfb2JqLCBtYWluID0gIlJPQyBDdXJ2ZSB3aXRoIE9wdGltYWwgVGhyZXNob2xkIikNCmFibGluZShhID0gMCwgYiA9IDEsIGx0eSA9IDIsIGNvbCA9ICJncmF5IikNCnBvaW50cygxIC0gYmVzdF9jb29yZHNbInNwZWNpZmljaXR5Il0sIGJlc3RfY29vcmRzWyJzZW5zaXRpdml0eSJdLCBjb2wgPSAnI0NGQjg3QycsIHBjaCA9IDE5KQ0KdGV4dCgxIC0gYmVzdF9jb29yZHNbInNwZWNpZmljaXR5Il0sIGJlc3RfY29vcmRzWyJzZW5zaXRpdml0eSJdLA0KICAgICBsYWJlbHMgPSBwYXN0ZSgiVGhyZXNob2xkID0iLCByb3VuZChiZXN0X2Nvb3Jkc1sidGhyZXNob2xkIl0sIDIpKSwgcG9zID0gNCkNCmBgYA0KRm9yIE1heGltdW0gVkFMRCBSU0kgdGhlIG9wdGltYWwgdGhyZXNob2xkIGlzIDAuMzk5NSB3aXRoIGEgQVVDIG9mIDAuNTI2Mywgc2Vuc2l0aXZpdHkgb2YgMC40MDYwNDQyIGFuZCBzcGVjaWZpY2l0eSBvZiAwLjY1NjE3OTguDQoNCmBgYHtyfQ0KI2xvb2sgYXQvZGlzY292ZXIvY3JlYXRlIG1vcmUgbWVhbmluZ2Z1bCB0aHJlc2hvbGRzIGZvciBzdHJlbmd0aCBtZXRyaWNzIHJlbGF0aW5nIHRvIExCIGluanVyeSByaXNrLCB0aGVuIHRlc3QgY29uZmlybSB0aHJlc2hvbGQgaXMgdmFsdWFibGUgKyBpbnRlcnByZXQNCmFsbF9DTUpfaW5jaWRlbnQgPC0gIGFsbF9DTUpfaW5jaWRlbnQgJT4lDQogIG11dGF0ZShhYm92ZV90aHJlc2hvbGQ9aWZlbHNlKE1heC5SU0kuTW9kaWZpZWQuVkFMRD49IDAuMzk5NSwgMSwwKSkjYWRkIG5ld2ZvdW5kIHRocmVzaG9sZA0KDQojRG9lcyBiZWluZyBhYm92ZSB0aGUgdGhyZXNob2xkIHJlbGF0ZSB0byBsb3dlciBib2R5IGluanVyeSByaXNrPw0KbW9kZWwgPC0gZ2xtKExCLkluanVyeX4gYWJvdmVfdGhyZXNob2xkLGRhdGE9YWxsX0NNSl9pbmNpZGVudCwgZmFtaWx5PSJiaW5vbWlhbCIpDQpzdW1tYXJ5KG1vZGVsKQ0KYGBgDQoNCg0KI0hvcCBKdW1wDQoxLk1heGltdW0gSnVtcCBIZWlnaHQNCmBgYHtyfQ0KYWxsX2hvcGp1bXBfaW5jaWRlbnQkTEIuSW5qdXJ5IDwtIGFzLmZhY3RvcihhbGxfaG9wanVtcF9pbmNpZGVudCRMQi5Jbmp1cnkpDQoNCmNwIDwtIGN1dHBvaW50cihhbGxfaG9wanVtcF9pbmNpZGVudCwgTWF4Lkp1bXAuSGVpZ2h0Li5jbS4gLCBMQi5Jbmp1cnksIG1ldGhvZD1tYXhpbWl6ZV9tZXRyaWMsIG1ldHJpYz15b3VkZW4pDQpwbG90KGNwKQ0Kc3VtbWFyeShjcCkNCmBgYA0KRm9yIE1heGltdW0gSnVtcCBIZWlnaHQgdGhlIG9wdGltYWwgY3V0cG9pbnQgaXMgMjUuNDg5IHdpdGggYSBBVUMgb2YgMC41MzMsIHNlbnNpdGl2aXR5IG9mIDAuNTI2MyBhbmQgc3BlY2lmaWNpdHkgb2YgMC41MzQyLg0KDQpgYGB7cn0NCiNST0Mgb2JqZWN0DQpyb2Nfb2JqIDwtIHJvYyhyZXNwb25zZSA9IGFsbF9ob3BqdW1wX2luY2lkZW50JExCLkluanVyeSwNCiAgICAgICAgICAgICAgIHByZWRpY3RvciA9IGFsbF9ob3BqdW1wX2luY2lkZW50JE1heC5KdW1wLkhlaWdodC4uY20uICwgI3Bvd2VyDQogICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiPiIpICAjIHVzZSAiPCIgaWYgaGlnaGVyIHZhbHVlcz0gaGlnaCByaXNrIHByZWRpY3QgJ05vJw0KICAgICAgICAgICAgICAgIyBpZiA+IHJlbC4gY29uLiBwb3dlciB0aGVuIGxvd2VyIHJpc2sNCiNwbG90IGN1cnZlDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIC0gTWF4aW11bSBKdW1wIEhlaWdodCIpDQphdWNfdmFsdWUgPC0gYXVjKHJvY19vYmopDQpwcmludChhdWNfdmFsdWUpDQpiZXN0X2Nvb3JkcyA8LSBjb29yZHMocm9jX29iaiwgImJlc3QiLCByZXQgPSBjKCJ0aHJlc2hvbGQiLCAic2Vuc2l0aXZpdHkiLCAic3BlY2lmaWNpdHkiKSwgYmVzdC5tZXRob2QgPSAieW91ZGVuIikNCmJlc3RfY29vcmRzDQoNCiNwbG90ICsgdGhyZXNob2xkDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIHdpdGggT3B0aW1hbCBUaHJlc2hvbGQiKQ0KYWJsaW5lKGEgPSAwLCBiID0gMSwgbHR5ID0gMiwgY29sID0gImdyYXkiKQ0KcG9pbnRzKDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sIGNvbCA9ICcjQ0ZCODdDJywgcGNoID0gMTkpDQp0ZXh0KDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sDQogICAgIGxhYmVscyA9IHBhc3RlKCJUaHJlc2hvbGQgPSIsIHJvdW5kKGJlc3RfY29vcmRzWyJ0aHJlc2hvbGQiXSwgMikpLCBwb3MgPSA0KQ0KYGBgDQpGb3IgTWF4aW11bSBKdW1wIEhlaWdodCB0aGUgb3B0aW1hbCB0aHJlc2hvbGQgaXMgMjUuNDMzNSB3aXRoIGEgQVVDIG9mIDAuNTMzLCBzZW5zaXRpdml0eSBvZiAwLjUzNDE4MjMgYW5kIHNwZWNpZmljaXR5IG9mIDAuNTI2MzE1OC4NCg0KYGBge3J9DQojbG9vayBhdC9kaXNjb3Zlci9jcmVhdGUgbW9yZSBtZWFuaW5nZnVsIHRocmVzaG9sZHMgZm9yIHN0cmVuZ3RoIG1ldHJpY3MgcmVsYXRpbmcgdG8gTEIgaW5qdXJ5IHJpc2ssIHRoZW4gdGVzdCBjb25maXJtIHRocmVzaG9sZCBpcyB2YWx1YWJsZSArIGludGVycHJldA0KYWxsX2hvcGp1bXBfaW5jaWRlbnQgPC0gIGFsbF9ob3BqdW1wX2luY2lkZW50ICU+JQ0KICBtdXRhdGUoYWJvdmVfdGhyZXNob2xkPWlmZWxzZShNYXguSnVtcC5IZWlnaHQuLmNtLj49IDI1LjQ4OSwgMSwwKSkjYWRkIG5ld2ZvdW5kIHRocmVzaG9sZA0KDQojRG9lcyBiZWluZyBhYm92ZSB0aGUgdGhyZXNob2xkIHJlbGF0ZSB0byBsb3dlciBib2R5IGluanVyeSByaXNrPw0KbW9kZWwgPC0gZ2xtKExCLkluanVyeX4gYWJvdmVfdGhyZXNob2xkLGRhdGE9YWxsX2hvcGp1bXBfaW5jaWRlbnQsIGZhbWlseT0iYmlub21pYWwiKQ0Kc3VtbWFyeShtb2RlbCkNCmBgYA0KDQoyLk1lYW4gUlNJIEZsaWdodCBDb250YWN0IFRpbWUNCmBgYHtyfQ0KYWxsX2hvcGp1bXBfaW5jaWRlbnQkTEIuSW5qdXJ5IDwtIGFzLmZhY3RvcihhbGxfaG9wanVtcF9pbmNpZGVudCRMQi5Jbmp1cnkpDQoNCmNwIDwtIGN1dHBvaW50cihhbGxfaG9wanVtcF9pbmNpZGVudCwgTWVhbi5SU0kuLkZsaWdodC5Db250YWN0LlRpbWUuICwgTEIuSW5qdXJ5LCBtZXRob2Q9bWF4aW1pemVfbWV0cmljLCBtZXRyaWM9eW91ZGVuKQ0KcGxvdChjcCkNCnN1bW1hcnkoY3ApDQpgYGANCkZvciBNZWFuIFJTSSBGbGlnaHQgQ29udGFjdCBUaW1lIHRoZSBvcHRpbWFsIGN1dHBvaW50IGlzIDIuNDQxIHdpdGggYSBBVUMgb2YgMC41MDg2LCBzZW5zaXRpdml0eSBvZiAwLjQwMTcgYW5kIHNwZWNpZmljaXR5IG9mIDAuNjM4Ny4NCg0KYGBge3J9DQojUk9DIG9iamVjdA0Kcm9jX29iaiA8LSByb2MocmVzcG9uc2UgPSBhbGxfaG9wanVtcF9pbmNpZGVudCRMQi5Jbmp1cnksDQogICAgICAgICAgICAgICBwcmVkaWN0b3IgPSBhbGxfaG9wanVtcF9pbmNpZGVudCRNZWFuLlJTSS4uRmxpZ2h0LkNvbnRhY3QuVGltZS4gLCAjcG93ZXINCiAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICI+IikgICMgdXNlICI8IiBpZiBoaWdoZXIgdmFsdWVzPSBoaWdoIHJpc2sgcHJlZGljdCAnTm8nDQogICAgICAgICAgICAgICAjIGlmID4gcmVsLiBjb24uIHBvd2VyIHRoZW4gbG93ZXIgcmlzaw0KI3Bsb3QgY3VydmUNCnBsb3Qocm9jX29iaiwgbWFpbiA9ICJST0MgQ3VydmUgLSBNZWFuIFJTSSBGbGlnaHQgQ29udGFjdCBUaW1lIikNCmF1Y192YWx1ZSA8LSBhdWMocm9jX29iaikNCnByaW50KGF1Y192YWx1ZSkNCmJlc3RfY29vcmRzIDwtIGNvb3Jkcyhyb2Nfb2JqLCAiYmVzdCIsIHJldCA9IGMoInRocmVzaG9sZCIsICJzZW5zaXRpdml0eSIsICJzcGVjaWZpY2l0eSIpLCBiZXN0Lm1ldGhvZCA9ICJ5b3VkZW4iKQ0KYmVzdF9jb29yZHMNCg0KI3Bsb3QgKyB0aHJlc2hvbGQNCnBsb3Qocm9jX29iaiwgbWFpbiA9ICJST0MgQ3VydmUgd2l0aCBPcHRpbWFsIFRocmVzaG9sZCIpDQphYmxpbmUoYSA9IDAsIGIgPSAxLCBsdHkgPSAyLCBjb2wgPSAiZ3JheSIpDQpwb2ludHMoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwgY29sID0gJyNDRkI4N0MnLCBwY2ggPSAxOSkNCnRleHQoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwNCiAgICAgbGFiZWxzID0gcGFzdGUoIlRocmVzaG9sZCA9Iiwgcm91bmQoYmVzdF9jb29yZHNbInRocmVzaG9sZCJdLCAyKSksIHBvcyA9IDQpDQpgYGANCkZvciBNZWFuIFJTSSBGbGlnaHQgQ29udGFjdCBUaW1lIHRoZSBvcHRpbWFsIHRocmVzaG9sZCBpcyAxLjggd2l0aCBhIEFVQyBvZiAwLjQ5MTQsIHNlbnNpdGl2aXR5IG9mIDAuMTY0NjU1OSBhbmQgc3BlY2lmaWNpdHkgb2YgMC44NTk5NDY1Lg0KDQpgYGB7cn0NCiNsb29rIGF0L2Rpc2NvdmVyL2NyZWF0ZSBtb3JlIG1lYW5pbmdmdWwgdGhyZXNob2xkcyBmb3Igc3RyZW5ndGggbWV0cmljcyByZWxhdGluZyB0byBMQiBpbmp1cnkgcmlzaywgdGhlbiB0ZXN0IGNvbmZpcm0gdGhyZXNob2xkIGlzIHZhbHVhYmxlICsgaW50ZXJwcmV0DQphbGxfaG9wanVtcF9pbmNpZGVudCA8LSAgYWxsX2hvcGp1bXBfaW5jaWRlbnQgJT4lDQogIG11dGF0ZShhYm92ZV90aHJlc2hvbGQ9aWZlbHNlKE1lYW4uUlNJLi5GbGlnaHQuQ29udGFjdC5UaW1lLj49IDIuNDQxLCAxLDApKSNhZGQgbmV3Zm91bmQgdGhyZXNob2xkDQoNCiNEb2VzIGJlaW5nIGFib3ZlIHRoZSB0aHJlc2hvbGQgcmVsYXRlIHRvIGxvd2VyIGJvZHkgaW5qdXJ5IHJpc2s/DQptb2RlbCA8LSBnbG0oTEIuSW5qdXJ5fiBhYm92ZV90aHJlc2hvbGQsZGF0YT1hbGxfaG9wanVtcF9pbmNpZGVudCwgZmFtaWx5PSJiaW5vbWlhbCIpDQpzdW1tYXJ5KG1vZGVsKQ0KYGBgDQoNCjMuQmVzdCBDb250YWN0IFRpbWUNCmBgYHtyfQ0KYWxsX2hvcGp1bXBfaW5jaWRlbnQkTEIuSW5qdXJ5IDwtIGFzLmZhY3RvcihhbGxfaG9wanVtcF9pbmNpZGVudCRMQi5Jbmp1cnkpDQoNCmNwIDwtIGN1dHBvaW50cihhbGxfaG9wanVtcF9pbmNpZGVudCwgQmVzdC5Db250YWN0LlRpbWUuLm1zLiAsIExCLkluanVyeSwgbWV0aG9kPW1heGltaXplX21ldHJpYywgbWV0cmljPXlvdWRlbikNCnBsb3QoY3ApDQpzdW1tYXJ5KGNwKQ0KYGBgDQpGb3IgQmVzdCBDb250YWN0IFRpbWUgdGhlIG9wdGltYWwgY3V0cG9pbnQgaXMgMC4xODQgd2l0aCBhIEFVQyBvZiAwLjU0NDIsIHNlbnNpdGl2aXR5IG9mIDAuNjk0OSBhbmQgc3BlY2lmaWNpdHkgb2YgMC40MjI3Lg0KDQpgYGB7cn0NCiNST0Mgb2JqZWN0DQpyb2Nfb2JqIDwtIHJvYyhyZXNwb25zZSA9IGFsbF9ob3BqdW1wX2luY2lkZW50JExCLkluanVyeSwNCiAgICAgICAgICAgICAgIHByZWRpY3RvciA9IGFsbF9ob3BqdW1wX2luY2lkZW50JEJlc3QuQ29udGFjdC5UaW1lLi5tcy4gLCAjcG93ZXINCiAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICI+IikgICMgdXNlICI8IiBpZiBoaWdoZXIgdmFsdWVzPSBoaWdoIHJpc2sgcHJlZGljdCAnTm8nDQogICAgICAgICAgICAgICAjIGlmID4gcmVsLiBjb24uIHBvd2VyIHRoZW4gbG93ZXIgcmlzaw0KI3Bsb3QgY3VydmUNCnBsb3Qocm9jX29iaiwgbWFpbiA9ICJST0MgQ3VydmUgLSBCZXN0IENvbnRhY3QgVGltZSIpDQphdWNfdmFsdWUgPC0gYXVjKHJvY19vYmopDQpwcmludChhdWNfdmFsdWUpDQpiZXN0X2Nvb3JkcyA8LSBjb29yZHMocm9jX29iaiwgImJlc3QiLCByZXQgPSBjKCJ0aHJlc2hvbGQiLCAic2Vuc2l0aXZpdHkiLCAic3BlY2lmaWNpdHkiKSwgYmVzdC5tZXRob2QgPSAieW91ZGVuIikNCmJlc3RfY29vcmRzDQoNCiNwbG90ICsgdGhyZXNob2xkDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIHdpdGggT3B0aW1hbCBUaHJlc2hvbGQiKQ0KYWJsaW5lKGEgPSAwLCBiID0gMSwgbHR5ID0gMiwgY29sID0gImdyYXkiKQ0KcG9pbnRzKDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sIGNvbCA9ICcjQ0ZCODdDJywgcGNoID0gMTkpDQp0ZXh0KDEgLSBiZXN0X2Nvb3Jkc1sic3BlY2lmaWNpdHkiXSwgYmVzdF9jb29yZHNbInNlbnNpdGl2aXR5Il0sDQogICAgIGxhYmVscyA9IHBhc3RlKCJUaHJlc2hvbGQgPSIsIHJvdW5kKGJlc3RfY29vcmRzWyJ0aHJlc2hvbGQiXSwgMikpLCBwb3MgPSA0KQ0KYGBgDQpGb3IgQmVzdCBDb250YWN0IFRpbWUgdGhlIG9wdGltYWwgdGhyZXNob2xkIGlzIDAuMTgzNSB3aXRoIGEgQVVDIG9mIDAuNTQ0MiAsIHNlbnNpdGl2aXR5IG9mIDAuNDIyNjk4OCBhbmQgc3BlY2lmaWNpdHkgb2YgMC42OTQ5MTUzLg0KDQpgYGB7cn0NCiNsb29rIGF0L2Rpc2NvdmVyL2NyZWF0ZSBtb3JlIG1lYW5pbmdmdWwgdGhyZXNob2xkcyBmb3Igc3RyZW5ndGggbWV0cmljcyByZWxhdGluZyB0byBMQiBpbmp1cnkgcmlzaywgdGhlbiB0ZXN0IGNvbmZpcm0gdGhyZXNob2xkIGlzIHZhbHVhYmxlICsgaW50ZXJwcmV0DQphbGxfaG9wanVtcF9pbmNpZGVudCA8LSAgYWxsX2hvcGp1bXBfaW5jaWRlbnQgJT4lDQogIG11dGF0ZShhYm92ZV90aHJlc2hvbGQ9aWZlbHNlKEJlc3QuQ29udGFjdC5UaW1lLi5tcy4+PSAwLjE4NCwgMSwwKSkjYWRkIG5ld2ZvdW5kIHRocmVzaG9sZA0KDQojRG9lcyBiZWluZyBhYm92ZSB0aGUgdGhyZXNob2xkIHJlbGF0ZSB0byBsb3dlciBib2R5IGluanVyeSByaXNrPw0KbW9kZWwgPC0gZ2xtKExCLkluanVyeX4gYWJvdmVfdGhyZXNob2xkLGRhdGE9YWxsX2hvcGp1bXBfaW5jaWRlbnQsIGZhbWlseT0iYmlub21pYWwiKQ0Kc3VtbWFyeShtb2RlbCkNCmBgYA0KDQojSXNvbWV0cmljIE1pZCBUaGlnaCBQdWxsDQoxLiBQZWFrIFZlcnRpY2FsIEZvcmNlDQpgYGB7cn0NCmFsbF9JTVRQX2luY2lkZW50JExCLkluanVyeSA8LSBhcy5mYWN0b3IoYWxsX0lNVFBfaW5jaWRlbnQkTEIuSW5qdXJ5KQ0KDQpjcCA8LSBjdXRwb2ludHIoYWxsX0lNVFBfaW5jaWRlbnQsIFBlYWsuVmVydGljYWwuRm9yY2UuLi5CTS4uTi5rZy4gLCBMQi5Jbmp1cnksIG1ldGhvZD1tYXhpbWl6ZV9tZXRyaWMsIG1ldHJpYz15b3VkZW4pDQpwbG90KGNwKQ0Kc3VtbWFyeShjcCkNCmBgYA0KRm9yUGVhayBWZXJ0aWNhbCBGb3JjZSB0aGUgb3B0aW1hbCBjdXRwb2ludCBpcyAzMC44MTMgd2l0aCBhIEFVQyBvZiAwLjUxMTYsIHNlbnNpdGl2aXR5IG9mIDAuODIxNCBhbmQgc3BlY2lmaWNpdHkgb2YgMC4yNTk2Lg0KDQpgYGB7cn0NCiNST0Mgb2JqZWN0DQpyb2Nfb2JqIDwtIHJvYyhyZXNwb25zZSA9IGFsbF9JTVRQX2luY2lkZW50JExCLkluanVyeSwNCiAgICAgICAgICAgICAgIHByZWRpY3RvciA9IGFsbF9JTVRQX2luY2lkZW50JFBlYWsuVmVydGljYWwuRm9yY2UuLi5CTS4uTi5rZy4gLCAjcG93ZXINCiAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICI+IikgICMgdXNlICI8IiBpZiBoaWdoZXIgdmFsdWVzPSBoaWdoIHJpc2sgcHJlZGljdCAnTm8nDQogICAgICAgICAgICAgICAjIGlmID4gcmVsLiBjb24uIHBvd2VyIHRoZW4gbG93ZXIgcmlzaw0KI3Bsb3QgY3VydmUNCnBsb3Qocm9jX29iaiwgbWFpbiA9ICJST0MgQ3VydmUgLSBQZWFrIFZlcnRpY2FsIEZvcmNlIikNCmF1Y192YWx1ZSA8LSBhdWMocm9jX29iaikNCnByaW50KGF1Y192YWx1ZSkNCmJlc3RfY29vcmRzIDwtIGNvb3Jkcyhyb2Nfb2JqLCAiYmVzdCIsIHJldCA9IGMoInRocmVzaG9sZCIsICJzZW5zaXRpdml0eSIsICJzcGVjaWZpY2l0eSIpLCBiZXN0Lm1ldGhvZCA9ICJ5b3VkZW4iKQ0KYmVzdF9jb29yZHMNCg0KI3Bsb3QgKyB0aHJlc2hvbGQNCnBsb3Qocm9jX29iaiwgbWFpbiA9ICJST0MgQ3VydmUgd2l0aCBPcHRpbWFsIFRocmVzaG9sZCIpDQphYmxpbmUoYSA9IDAsIGIgPSAxLCBsdHkgPSAyLCBjb2wgPSAiZ3JheSIpDQpwb2ludHMoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwgY29sID0gJyNDRkI4N0MnLCBwY2ggPSAxOSkNCnRleHQoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwNCiAgICAgbGFiZWxzID0gcGFzdGUoIlRocmVzaG9sZCA9Iiwgcm91bmQoYmVzdF9jb29yZHNbInRocmVzaG9sZCJdLCAyKSksIHBvcyA9IDQpDQpgYGANCkZvciBQZWFrIFZlcnRpY2FsIEZvcmMgdGhlIG9wdGltYWwgdGhyZXNob2xkIGlzIDMwLjU0NTUgd2l0aCBhIEFVQyBvZiAwLjUxMTYgLCBzZW5zaXRpdml0eSBvZiAwLjI1OTY0NjMgYW5kIHNwZWNpZmljaXR5IG9mIDAuODIxNDI4Ni4NCg0KYGBge3J9DQojbG9vayBhdC9kaXNjb3Zlci9jcmVhdGUgbW9yZSBtZWFuaW5nZnVsIHRocmVzaG9sZHMgZm9yIHN0cmVuZ3RoIG1ldHJpY3MgcmVsYXRpbmcgdG8gTEIgaW5qdXJ5IHJpc2ssIHRoZW4gdGVzdCBjb25maXJtIHRocmVzaG9sZCBpcyB2YWx1YWJsZSArIGludGVycHJldA0KYWxsX0lNVFBfaW5jaWRlbnQgPC0gIGFsbF9JTVRQX2luY2lkZW50ICU+JQ0KICBtdXRhdGUoYWJvdmVfdGhyZXNob2xkPWlmZWxzZShQZWFrLlZlcnRpY2FsLkZvcmNlLi4uQk0uLk4ua2cuPj0gMzAuODEzLCAxLDApKSNhZGQgbmV3Zm91bmQgdGhyZXNob2xkDQoNCiNEb2VzIGJlaW5nIGFib3ZlIHRoZSB0aHJlc2hvbGQgcmVsYXRlIHRvIGxvd2VyIGJvZHkgaW5qdXJ5IHJpc2s/DQptb2RlbCA8LSBnbG0oTEIuSW5qdXJ5fiBhYm92ZV90aHJlc2hvbGQsZGF0YT1hbGxfSU1UUF9pbmNpZGVudCwgZmFtaWx5PSJiaW5vbWlhbCIpDQpzdW1tYXJ5KG1vZGVsKQ0KYGBgDQoNCjIuUlBEIGF0IDIwMG1zDQpgYGB7cn0NCmFsbF9JTVRQX2luY2lkZW50JExCLkluanVyeSA8LSBhcy5mYWN0b3IoYWxsX0lNVFBfaW5jaWRlbnQkTEIuSW5qdXJ5KQ0KDQpjcCA8LSBjdXRwb2ludHIoYWxsX0lNVFBfaW5jaWRlbnQsIFJGRC4uLjIwMG1zLi5OLnMuICwgTEIuSW5qdXJ5LCBtZXRob2Q9bWF4aW1pemVfbWV0cmljLCBtZXRyaWM9eW91ZGVuKQ0KcGxvdChjcCkNCnN1bW1hcnkoY3ApDQpgYGANCkZvciBSUEQgYXQgMjAwbXMgdGhlIG9wdGltYWwgY3V0cG9pbnQgaXMgNDAzMi42Mzcgd2l0aCBhIEFVQyBvZiAwLjUyMDgsIHNlbnNpdGl2aXR5IG9mIDAuMzAwNiBhbmQgc3BlY2lmaWNpdHkgb2YgMC43NzkyLg0KDQpgYGB7cn0NCiNST0Mgb2JqZWN0DQpyb2Nfb2JqIDwtIHJvYyhyZXNwb25zZSA9IGFsbF9JTVRQX2luY2lkZW50JExCLkluanVyeSwNCiAgICAgICAgICAgICAgIHByZWRpY3RvciA9IGFsbF9JTVRQX2luY2lkZW50JFJGRC4uLjIwMG1zLi5OLnMuICwgI3Bvd2VyDQogICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiPiIpICAjIHVzZSAiPCIgaWYgaGlnaGVyIHZhbHVlcz0gaGlnaCByaXNrIHByZWRpY3QgJ05vJw0KICAgICAgICAgICAgICAgIyBpZiA+IHJlbC4gY29uLiBwb3dlciB0aGVuIGxvd2VyIHJpc2sNCiNwbG90IGN1cnZlDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIC0gUlBEIGF0IDIwMG1zIikNCmF1Y192YWx1ZSA8LSBhdWMocm9jX29iaikNCnByaW50KGF1Y192YWx1ZSkNCmJlc3RfY29vcmRzIDwtIGNvb3Jkcyhyb2Nfb2JqLCAiYmVzdCIsIHJldCA9IGMoInRocmVzaG9sZCIsICJzZW5zaXRpdml0eSIsICJzcGVjaWZpY2l0eSIpLCBiZXN0Lm1ldGhvZCA9ICJ5b3VkZW4iKQ0KYmVzdF9jb29yZHMNCg0KI3Bsb3QgKyB0aHJlc2hvbGQNCnBsb3Qocm9jX29iaiwgbWFpbiA9ICJST0MgQ3VydmUgd2l0aCBPcHRpbWFsIFRocmVzaG9sZCIpDQphYmxpbmUoYSA9IDAsIGIgPSAxLCBsdHkgPSAyLCBjb2wgPSAiZ3JheSIpDQpwb2ludHMoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwgY29sID0gJyNDRkI4N0MnLCBwY2ggPSAxOSkNCnRleHQoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwNCiAgICAgbGFiZWxzID0gcGFzdGUoIlRocmVzaG9sZCA9Iiwgcm91bmQoYmVzdF9jb29yZHNbInRocmVzaG9sZCJdLCAyKSksIHBvcyA9IDQpDQpgYGANCkZvciBSUEQgYXQgMjAwbXMgdGhlIG9wdGltYWwgdGhyZXNob2xkIGlzIDgzNTcuODU5IHdpdGggYSBBVUMgb2YgMC40NzkyICwgc2Vuc2l0aXZpdHkgb2YgMC45NzY2ODgxIGFuZCBzcGVjaWZpY2l0eSBvZiAwLjA3NzkyMjA4LiAgDQoNCmBgYHtyfQ0KI2xvb2sgYXQvZGlzY292ZXIvY3JlYXRlIG1vcmUgbWVhbmluZ2Z1bCB0aHJlc2hvbGRzIGZvciBzdHJlbmd0aCBtZXRyaWNzIHJlbGF0aW5nIHRvIExCIGluanVyeSByaXNrLCB0aGVuIHRlc3QgY29uZmlybSB0aHJlc2hvbGQgaXMgdmFsdWFibGUgKyBpbnRlcnByZXQNCmFsbF9JTVRQX2luY2lkZW50IDwtICBhbGxfSU1UUF9pbmNpZGVudCAlPiUNCiAgbXV0YXRlKGFib3ZlX3RocmVzaG9sZD1pZmVsc2UoUkZELi4uMjAwbXMuLk4ucy4+PSA4MzU3Ljg1OSwgMSwwKSkjYWRkIG5ld2ZvdW5kIHRocmVzaG9sZA0KDQojRG9lcyBiZWluZyBhYm92ZSB0aGUgdGhyZXNob2xkIHJlbGF0ZSB0byBsb3dlciBib2R5IGluanVyeSByaXNrPw0KbW9kZWwgPC0gZ2xtKExCLkluanVyeX4gYWJvdmVfdGhyZXNob2xkLGRhdGE9YWxsX0lNVFBfaW5jaWRlbnQsIGZhbWlseT0iYmlub21pYWwiKQ0Kc3VtbWFyeShtb2RlbCkNCmBgYA0KDQozLiBGb3JjZSBhdCAyMDBtcw0KYGBge3J9DQphbGxfSU1UUF9pbmNpZGVudCRMQi5Jbmp1cnkgPC0gYXMuZmFjdG9yKGFsbF9JTVRQX2luY2lkZW50JExCLkluanVyeSkNCg0KY3AgPC0gY3V0cG9pbnRyKGFsbF9JTVRQX2luY2lkZW50LCBGb3JjZS5hdC4yMDBtcy4uLkJNLi5OLmtnLiAsIExCLkluanVyeSwgbWV0aG9kPW1heGltaXplX21ldHJpYywgbWV0cmljPXlvdWRlbikNCnBsb3QoY3ApDQpzdW1tYXJ5KGNwKQ0KYGBgDQpGb3IgRm9yY2UgYXQgMjAwbXMgdGhlIG9wdGltYWwgY3V0cG9pbnQgaXMgMjQuMjU0IHdpdGggYSBBVUMgb2YgMC41MDcsIHNlbnNpdGl2aXR5IG9mIDAuMzcxNCBhbmQgc3BlY2lmaWNpdHkgb2YgMC43MDc4Lg0KDQpgYGB7cn0NCiNST0Mgb2JqZWN0DQpyb2Nfb2JqIDwtIHJvYyhyZXNwb25zZSA9IGFsbF9JTVRQX2luY2lkZW50JExCLkluanVyeSwNCiAgICAgICAgICAgICAgIHByZWRpY3RvciA9IGFsbF9JTVRQX2luY2lkZW50JEZvcmNlLmF0LjIwMG1zLi4uQk0uLk4ua2cuICwgI3Bvd2VyDQogICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiPiIpICAjIHVzZSAiPCIgaWYgaGlnaGVyIHZhbHVlcz0gaGlnaCByaXNrIHByZWRpY3QgJ05vJw0KICAgICAgICAgICAgICAgIyBpZiA+IHJlbC4gY29uLiBwb3dlciB0aGVuIGxvd2VyIHJpc2sNCiNwbG90IGN1cnZlDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIC0gRm9yY2UgYXQgMjAwbXMiKQ0KYXVjX3ZhbHVlIDwtIGF1Yyhyb2Nfb2JqKQ0KcHJpbnQoYXVjX3ZhbHVlKQ0KYmVzdF9jb29yZHMgPC0gY29vcmRzKHJvY19vYmosICJiZXN0IiwgcmV0ID0gYygidGhyZXNob2xkIiwgInNlbnNpdGl2aXR5IiwgInNwZWNpZmljaXR5IiksIGJlc3QubWV0aG9kID0gInlvdWRlbiIpDQpiZXN0X2Nvb3Jkcw0KDQojcGxvdCArIHRocmVzaG9sZA0KcGxvdChyb2Nfb2JqLCBtYWluID0gIlJPQyBDdXJ2ZSB3aXRoIE9wdGltYWwgVGhyZXNob2xkIikNCmFibGluZShhID0gMCwgYiA9IDEsIGx0eSA9IDIsIGNvbCA9ICJncmF5IikNCnBvaW50cygxIC0gYmVzdF9jb29yZHNbInNwZWNpZmljaXR5Il0sIGJlc3RfY29vcmRzWyJzZW5zaXRpdml0eSJdLCBjb2wgPSAnI0NGQjg3QycsIHBjaCA9IDE5KQ0KdGV4dCgxIC0gYmVzdF9jb29yZHNbInNwZWNpZmljaXR5Il0sIGJlc3RfY29vcmRzWyJzZW5zaXRpdml0eSJdLA0KICAgICBsYWJlbHMgPSBwYXN0ZSgiVGhyZXNob2xkID0iLCByb3VuZChiZXN0X2Nvb3Jkc1sidGhyZXNob2xkIl0sIDIpKSwgcG9zID0gNCkNCmBgYA0KRm9yIEZvcmNlIGF0IDIwMG1zIHRoZSBvcHRpbWFsIHRocmVzaG9sZCBpcyAxNy42MjA1IHdpdGggYSBBVUMgb2YgMC40OTMgLCBzZW5zaXRpdml0eSBvZiAwLjMxMjcwMSBhbmQgc3BlY2lmaWNpdHkgb2YgMC43NDAyNTk3Lg0KDQpgYGB7cn0NCiNsb29rIGF0L2Rpc2NvdmVyL2NyZWF0ZSBtb3JlIG1lYW5pbmdmdWwgdGhyZXNob2xkcyBmb3Igc3RyZW5ndGggbWV0cmljcyByZWxhdGluZyB0byBMQiBpbmp1cnkgcmlzaywgdGhlbiB0ZXN0IGNvbmZpcm0gdGhyZXNob2xkIGlzIHZhbHVhYmxlICsgaW50ZXJwcmV0DQphbGxfSU1UUF9pbmNpZGVudCA8LSAgYWxsX0lNVFBfaW5jaWRlbnQgJT4lDQogIG11dGF0ZShhYm92ZV90aHJlc2hvbGQ9aWZlbHNlKEZvcmNlLmF0LjIwMG1zLi4uQk0uLk4ua2cuPj0gMjQuMjU0LCAxLDApKSNhZGQgbmV3Zm91bmQgdGhyZXNob2xkDQoNCiNEb2VzIGJlaW5nIGFib3ZlIHRoZSB0aHJlc2hvbGQgcmVsYXRlIHRvIGxvd2VyIGJvZHkgaW5qdXJ5IHJpc2s/DQptb2RlbCA8LSBnbG0oTEIuSW5qdXJ5fiBhYm92ZV90aHJlc2hvbGQsZGF0YT1hbGxfSU1UUF9pbmNpZGVudCwgZmFtaWx5PSJiaW5vbWlhbCIpDQpzdW1tYXJ5KG1vZGVsKQ0KYGBgDQoNCjQuIERTSQ0KYGBge3J9DQphbGxfSU1UUF9pbmNpZGVudCRMQi5Jbmp1cnkgPC0gYXMuZmFjdG9yKGFsbF9JTVRQX2luY2lkZW50JExCLkluanVyeSkNCg0KY3AgPC0gY3V0cG9pbnRyKGFsbF9JTVRQX2luY2lkZW50LCBEU0kgLCBMQi5Jbmp1cnksIG1ldGhvZD1tYXhpbWl6ZV9tZXRyaWMsIG1ldHJpYz15b3VkZW4pDQpwbG90KGNwKQ0Kc3VtbWFyeShjcCkNCmBgYA0KRm9yIERTSSB0aGUgb3B0aW1hbCBjdXRwb2ludCBpcyAwLjU5IHdpdGggYSBBVUMgb2YgMC41MDA1LCBzZW5zaXRpdml0eSBvZiAwLjIyOTEgYW5kIHNwZWNpZmljaXR5IG9mIDAuODU3MS4NCg0KYGBge3J9DQojUk9DIG9iamVjdA0Kcm9jX29iaiA8LSByb2MocmVzcG9uc2UgPSBhbGxfSU1UUF9pbmNpZGVudCRMQi5Jbmp1cnksDQogICAgICAgICAgICAgICBwcmVkaWN0b3IgPSBhbGxfSU1UUF9pbmNpZGVudCREU0kgLCAjcG93ZXINCiAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICI+IikgICMgdXNlICI8IiBpZiBoaWdoZXIgdmFsdWVzPSBoaWdoIHJpc2sgcHJlZGljdCAnTm8nDQogICAgICAgICAgICAgICAjIGlmID4gcmVsLiBjb24uIHBvd2VyIHRoZW4gbG93ZXIgcmlzaw0KI3Bsb3QgY3VydmUNCnBsb3Qocm9jX29iaiwgbWFpbiA9ICJST0MgQ3VydmUgLSBEeW5hbWljIFN0cmVuZ3RoIEluZGV4IikNCmF1Y192YWx1ZSA8LSBhdWMocm9jX29iaikNCnByaW50KGF1Y192YWx1ZSkNCmJlc3RfY29vcmRzIDwtIGNvb3Jkcyhyb2Nfb2JqLCAiYmVzdCIsIHJldCA9IGMoInRocmVzaG9sZCIsICJzZW5zaXRpdml0eSIsICJzcGVjaWZpY2l0eSIpLCBiZXN0Lm1ldGhvZCA9ICJ5b3VkZW4iKQ0KYmVzdF9jb29yZHMNCg0KI3Bsb3QgKyB0aHJlc2hvbGQNCnBsb3Qocm9jX29iaiwgbWFpbiA9ICJST0MgQ3VydmUgd2l0aCBPcHRpbWFsIFRocmVzaG9sZCIpDQphYmxpbmUoYSA9IDAsIGIgPSAxLCBsdHkgPSAyLCBjb2wgPSAiZ3JheSIpDQpwb2ludHMoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwgY29sID0gJyNDRkI4N0MnLCBwY2ggPSAxOSkNCnRleHQoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwNCiAgICAgbGFiZWxzID0gcGFzdGUoIlRocmVzaG9sZCA9Iiwgcm91bmQoYmVzdF9jb29yZHNbInRocmVzaG9sZCJdLCAyKSksIHBvcyA9IDQpDQpgYGANCkZvciBEU0kgdGhlIG9wdGltYWwgdGhyZXNob2xkIGlzIDAuMjM1IHdpdGggYSBBVUMgb2YgMC40OTk1ICwgc2Vuc2l0aXZpdHkgb2YgMC4yNTgwMzg2IGFuZCBzcGVjaWZpY2l0eSBvZiAwLjgxMTY4ODMuDQoNCmBgYHtyfQ0KI2xvb2sgYXQvZGlzY292ZXIvY3JlYXRlIG1vcmUgbWVhbmluZ2Z1bCB0aHJlc2hvbGRzIGZvciBzdHJlbmd0aCBtZXRyaWNzIHJlbGF0aW5nIHRvIExCIGluanVyeSByaXNrLCB0aGVuIHRlc3QgY29uZmlybSB0aHJlc2hvbGQgaXMgdmFsdWFibGUgKyBpbnRlcnByZXQNCmFsbF9JTVRQX2luY2lkZW50IDwtICBhbGxfSU1UUF9pbmNpZGVudCAlPiUNCiAgbXV0YXRlKGFib3ZlX3RocmVzaG9sZD1pZmVsc2UoRFNJPj0gMC41OSwgMSwwKSkjYWRkIG5ld2ZvdW5kIHRocmVzaG9sZA0KDQojRG9lcyBiZWluZyBhYm92ZSB0aGUgdGhyZXNob2xkIHJlbGF0ZSB0byBsb3dlciBib2R5IGluanVyeSByaXNrPw0KbW9kZWwgPC0gZ2xtKExCLkluanVyeX4gYWJvdmVfdGhyZXNob2xkLGRhdGE9YWxsX0lNVFBfaW5jaWRlbnQsIGZhbWlseT0iYmlub21pYWwiKQ0Kc3VtbWFyeShtb2RlbCkNCmBgYA0KDQojU2luZ2xlIExlZyBKdW1wDQoxLk1heGltdW0gSnVtcCBIZWlnaHQNCmBgYHtyfQ0KYWxsX1NMSl9pbmNpZGVudCRMQi5Jbmp1cnkgPC0gYXMuZmFjdG9yKGFsbF9TTEpfaW5jaWRlbnQkTEIuSW5qdXJ5KQ0KDQpjcCA8LSBjdXRwb2ludHIoYWxsX1NMSl9pbmNpZGVudCwgTWF4Lkp1bXAuSGVpZ2h0Li5jbS4gLCBMQi5Jbmp1cnksIG1ldGhvZD1tYXhpbWl6ZV9tZXRyaWMsIG1ldHJpYz15b3VkZW4pDQpwbG90KGNwKQ0Kc3VtbWFyeShjcCkNCmBgYA0KRm9yIE1heGltdW0gSnVtcCBIZWlnaHQgdGhlIG9wdGltYWwgY3V0cG9pbnQgaXMgMTkuMjIzIHdpdGggYSBBVUMgb2YgMC42MTQ3LCBzZW5zaXRpdml0eSBvZiAwLjM2MjUgYW5kIHNwZWNpZmljaXR5IG9mIDAuODg4OS4NCg0KYGBge3J9DQojUk9DIG9iamVjdA0Kcm9jX29iaiA8LSByb2MocmVzcG9uc2UgPSBhbGxfU0xKX2luY2lkZW50JExCLkluanVyeSwNCiAgICAgICAgICAgICAgIHByZWRpY3RvciA9IGFsbF9TTEpfaW5jaWRlbnQkTWF4Lkp1bXAuSGVpZ2h0Li5jbS4gLCAjcG93ZXINCiAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICI+IikgICMgdXNlICI8IiBpZiBoaWdoZXIgdmFsdWVzPSBoaWdoIHJpc2sgcHJlZGljdCAnTm8nDQogICAgICAgICAgICAgICAjIGlmID4gcmVsLiBjb24uIHBvd2VyIHRoZW4gbG93ZXIgcmlzaw0KI3Bsb3QgY3VydmUNCnBsb3Qocm9jX29iaiwgbWFpbiA9ICJST0MgQ3VydmUgLSBNYXhpbXVtIEp1bXAgSGVpZ2h0IikNCmF1Y192YWx1ZSA8LSBhdWMocm9jX29iaikNCnByaW50KGF1Y192YWx1ZSkNCmJlc3RfY29vcmRzIDwtIGNvb3Jkcyhyb2Nfb2JqLCAiYmVzdCIsIHJldCA9IGMoInRocmVzaG9sZCIsICJzZW5zaXRpdml0eSIsICJzcGVjaWZpY2l0eSIpLCBiZXN0Lm1ldGhvZCA9ICJ5b3VkZW4iKQ0KYmVzdF9jb29yZHMNCg0KI3Bsb3QgKyB0aHJlc2hvbGQNCnBsb3Qocm9jX29iaiwgbWFpbiA9ICJST0MgQ3VydmUgd2l0aCBPcHRpbWFsIFRocmVzaG9sZCIpDQphYmxpbmUoYSA9IDAsIGIgPSAxLCBsdHkgPSAyLCBjb2wgPSAiZ3JheSIpDQpwb2ludHMoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwgY29sID0gJyNDRkI4N0MnLCBwY2ggPSAxOSkNCnRleHQoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwNCiAgICAgbGFiZWxzID0gcGFzdGUoIlRocmVzaG9sZCA9Iiwgcm91bmQoYmVzdF9jb29yZHNbInRocmVzaG9sZCJdLCAyKSksIHBvcyA9IDQpDQpgYGANCkZvciBNYXhpbXVtIEp1bXAgSGVpZ2h0IHRoZSBvcHRpbWFsIHRocmVzaG9sZCBpcyAyNC45NTMgd2l0aCBhIEFVQyBvZiAwLjM4NTMgLCBzZW5zaXRpdml0eSBvZiAwLjk4OTcxNzIgYW5kIHNwZWNpZmljaXR5IG9mIDAuMDI3Nzc3NzguICAgDQoNCmBgYHtyfQ0KI2xvb2sgYXQvZGlzY292ZXIvY3JlYXRlIG1vcmUgbWVhbmluZ2Z1bCB0aHJlc2hvbGRzIGZvciBzdHJlbmd0aCBtZXRyaWNzIHJlbGF0aW5nIHRvIExCIGluanVyeSByaXNrLCB0aGVuIHRlc3QgY29uZmlybSB0aHJlc2hvbGQgaXMgdmFsdWFibGUgKyBpbnRlcnByZXQNCmFsbF9TTEpfaW5jaWRlbnQgPC0gIGFsbF9TTEpfaW5jaWRlbnQgJT4lDQogIG11dGF0ZShhYm92ZV90aHJlc2hvbGQ9aWZlbHNlKE1heC5KdW1wLkhlaWdodC4uY20uPj0gMTkuMjIzLCAxLDApKSNhZGQgbmV3Zm91bmQgdGhyZXNob2xkDQoNCiNEb2VzIGJlaW5nIGFib3ZlIHRoZSB0aHJlc2hvbGQgcmVsYXRlIHRvIGxvd2VyIGJvZHkgaW5qdXJ5IHJpc2s/DQptb2RlbCA8LSBnbG0oTEIuSW5qdXJ5fiBhYm92ZV90aHJlc2hvbGQsZGF0YT1hbGxfU0xKX2luY2lkZW50LCBmYW1pbHk9ImJpbm9taWFsIikNCnN1bW1hcnkobW9kZWwpDQpgYGANCg0KMi5KdW1wIEhlaWdodCBGbGlnaHQgVGltZQ0KYGBge3J9DQphbGxfU0xKX2luY2lkZW50JExCLkluanVyeSA8LSBhcy5mYWN0b3IoYWxsX1NMSl9pbmNpZGVudCRMQi5Jbmp1cnkpDQoNCmNwIDwtIGN1dHBvaW50cihhbGxfU0xKX2luY2lkZW50LCBKdW1wLkhlaWdodC4uRmxpZ2h0LlRpbWUuLi5jbS4gLCBMQi5Jbmp1cnksIG1ldGhvZD1tYXhpbWl6ZV9tZXRyaWMsIG1ldHJpYz15b3VkZW4pDQpwbG90KGNwKQ0Kc3VtbWFyeShjcCkNCmBgYA0KRm9yIEp1bXAgSGVpZ2h0IEZsaWdodCBUaW1lIHRoZSBvcHRpbWFsIGN1dHBvaW50IGlzIDE3LjAyNyB3aXRoIGEgQVVDIG9mIDAuNTkwNCwgc2Vuc2l0aXZpdHkgb2YgMC4zMjY1IGFuZCBzcGVjaWZpY2l0eSBvZiAwLjg3NS4NCg0KYGBge3J9DQojUk9DIG9iamVjdA0Kcm9jX29iaiA8LSByb2MocmVzcG9uc2UgPSBhbGxfU0xKX2luY2lkZW50JExCLkluanVyeSwNCiAgICAgICAgICAgICAgIHByZWRpY3RvciA9IGFsbF9TTEpfaW5jaWRlbnQkSnVtcC5IZWlnaHQuLkZsaWdodC5UaW1lLi4uY20uICwgI3Bvd2VyDQogICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiPiIpICAjIHVzZSAiPCIgaWYgaGlnaGVyIHZhbHVlcz0gaGlnaCByaXNrIHByZWRpY3QgJ05vJw0KICAgICAgICAgICAgICAgIyBpZiA+IHJlbC4gY29uLiBwb3dlciB0aGVuIGxvd2VyIHJpc2sNCiNwbG90IGN1cnZlDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIC0gSnVtcCBIZWlnaHQgRmxpZ2h0IFRpbWUiKQ0KYXVjX3ZhbHVlIDwtIGF1Yyhyb2Nfb2JqKQ0KcHJpbnQoYXVjX3ZhbHVlKQ0KYmVzdF9jb29yZHMgPC0gY29vcmRzKHJvY19vYmosICJiZXN0IiwgcmV0ID0gYygidGhyZXNob2xkIiwgInNlbnNpdGl2aXR5IiwgInNwZWNpZmljaXR5IiksIGJlc3QubWV0aG9kID0gInlvdWRlbiIpDQpiZXN0X2Nvb3Jkcw0KDQojcGxvdCArIHRocmVzaG9sZA0KcGxvdChyb2Nfb2JqLCBtYWluID0gIlJPQyBDdXJ2ZSB3aXRoIE9wdGltYWwgVGhyZXNob2xkIikNCmFibGluZShhID0gMCwgYiA9IDEsIGx0eSA9IDIsIGNvbCA9ICJncmF5IikNCnBvaW50cygxIC0gYmVzdF9jb29yZHNbInNwZWNpZmljaXR5Il0sIGJlc3RfY29vcmRzWyJzZW5zaXRpdml0eSJdLCBjb2wgPSAnI0NGQjg3QycsIHBjaCA9IDE5KQ0KdGV4dCgxIC0gYmVzdF9jb29yZHNbInNwZWNpZmljaXR5Il0sIGJlc3RfY29vcmRzWyJzZW5zaXRpdml0eSJdLA0KICAgICBsYWJlbHMgPSBwYXN0ZSgiVGhyZXNob2xkID0iLCByb3VuZChiZXN0X2Nvb3Jkc1sidGhyZXNob2xkIl0sIDIpKSwgcG9zID0gNCkNCmBgYA0KRm9yIEp1bXAgSGVpZ2h0IEZsaWdodCBUaW1lIHRoZSBvcHRpbWFsIHRocmVzaG9sZCBpcyAyMy40MDY1OCB3aXRoIGEgQVVDIG9mIDAuNDA5NiAsIHNlbnNpdGl2aXR5IG9mIDAuOTg5NzE3MiBhbmQgc3BlY2lmaWNpdHkgb2YgMC4wMjc3Nzc3OC4gICAgIDE3LjAyNw0KDQpgYGB7cn0NCiNsb29rIGF0L2Rpc2NvdmVyL2NyZWF0ZSBtb3JlIG1lYW5pbmdmdWwgdGhyZXNob2xkcyBmb3Igc3RyZW5ndGggbWV0cmljcyByZWxhdGluZyB0byBMQiBpbmp1cnkgcmlzaywgdGhlbiB0ZXN0IGNvbmZpcm0gdGhyZXNob2xkIGlzIHZhbHVhYmxlICsgaW50ZXJwcmV0DQphbGxfU0xKX2luY2lkZW50IDwtICBhbGxfU0xKX2luY2lkZW50ICU+JQ0KICBtdXRhdGUoYWJvdmVfdGhyZXNob2xkPWlmZWxzZShKdW1wLkhlaWdodC4uRmxpZ2h0LlRpbWUuLi5jbS4+PSAxNy4wMjcsIDEsMCkpI2FkZCBuZXdmb3VuZCB0aHJlc2hvbGQNCg0KI0RvZXMgYmVpbmcgYWJvdmUgdGhlIHRocmVzaG9sZCByZWxhdGUgdG8gbG93ZXIgYm9keSBpbmp1cnkgcmlzaz8NCm1vZGVsIDwtIGdsbShMQi5Jbmp1cnl+IGFib3ZlX3RocmVzaG9sZCxkYXRhPWFsbF9TTEpfaW5jaWRlbnQsIGZhbWlseT0iYmlub21pYWwiKQ0Kc3VtbWFyeShtb2RlbCkNCmBgYA0KDQozLkxhbmRpbmcgUlBEDQpgYGB7cn0NCmFsbF9TTEpfaW5jaWRlbnQkTEIuSW5qdXJ5IDwtIGFzLmZhY3RvcihhbGxfU0xKX2luY2lkZW50JExCLkluanVyeSkNCg0KY3AgPC0gY3V0cG9pbnRyKGFsbF9TTEpfaW5jaWRlbnQsIExhbmRpbmcuUkZELi5OLnMuICwgTEIuSW5qdXJ5LCBtZXRob2Q9bWF4aW1pemVfbWV0cmljLCBtZXRyaWM9eW91ZGVuKQ0KcGxvdChjcCkNCnN1bW1hcnkoY3ApDQpgYGANCkZvciBMYW5kaW5nIFJQRCB0aGUgb3B0aW1hbCBjdXRwb2ludCBpcyA9MzEwNjEuMTYgd2l0aCBhIEFVQyBvZiAwLjUzNDcsIHNlbnNpdGl2aXR5IG9mIDAuNDk4NyBhbmQgc3BlY2lmaWNpdHkgb2YgMC42ODA2Lg0KDQpgYGB7cn0NCiNST0Mgb2JqZWN0DQpyb2Nfb2JqIDwtIHJvYyhyZXNwb25zZSA9IGFsbF9TTEpfaW5jaWRlbnQkTEIuSW5qdXJ5LA0KICAgICAgICAgICAgICAgcHJlZGljdG9yID0gYWxsX1NMSl9pbmNpZGVudCRMYW5kaW5nLlJGRC4uTi5zLiAsICNwb3dlcg0KICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gIj4iKSAgIyB1c2UgIjwiIGlmIGhpZ2hlciB2YWx1ZXM9IGhpZ2ggcmlzayBwcmVkaWN0ICdObycNCiAgICAgICAgICAgICAgICMgaWYgPiByZWwuIGNvbi4gcG93ZXIgdGhlbiBsb3dlciByaXNrDQojcGxvdCBjdXJ2ZQ0KcGxvdChyb2Nfb2JqLCBtYWluID0gIlJPQyBDdXJ2ZSAtIExhbmRpbmcgUlBEIikNCmF1Y192YWx1ZSA8LSBhdWMocm9jX29iaikNCnByaW50KGF1Y192YWx1ZSkNCmJlc3RfY29vcmRzIDwtIGNvb3Jkcyhyb2Nfb2JqLCAiYmVzdCIsIHJldCA9IGMoInRocmVzaG9sZCIsICJzZW5zaXRpdml0eSIsICJzcGVjaWZpY2l0eSIpLCBiZXN0Lm1ldGhvZCA9ICJ5b3VkZW4iKQ0KYmVzdF9jb29yZHMNCg0KI3Bsb3QgKyB0aHJlc2hvbGQNCnBsb3Qocm9jX29iaiwgbWFpbiA9ICJST0MgQ3VydmUgd2l0aCBPcHRpbWFsIFRocmVzaG9sZCIpDQphYmxpbmUoYSA9IDAsIGIgPSAxLCBsdHkgPSAyLCBjb2wgPSAiZ3JheSIpDQpwb2ludHMoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwgY29sID0gJyNDRkI4N0MnLCBwY2ggPSAxOSkNCnRleHQoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwNCiAgICAgbGFiZWxzID0gcGFzdGUoIlRocmVzaG9sZCA9Iiwgcm91bmQoYmVzdF9jb29yZHNbInRocmVzaG9sZCJdLCAyKSksIHBvcyA9IDQpDQpgYGANCkZvciBMYW5kaW5nIFJQRCB0aGUgb3B0aW1hbCB0aHJlc2hvbGQgaXMgMjQzOTUuMDEgd2l0aCBhIEFVQyBvZiAwLjQ2NTMgLCBzZW5zaXRpdml0eSBvZiAwLjE0OTEwMDMgYW5kIHNwZWNpZmljaXR5IG9mIDAuOTQ0NDQ0NC4gICAgIA0KDQpgYGB7cn0NCiNsb29rIGF0L2Rpc2NvdmVyL2NyZWF0ZSBtb3JlIG1lYW5pbmdmdWwgdGhyZXNob2xkcyBmb3Igc3RyZW5ndGggbWV0cmljcyByZWxhdGluZyB0byBMQiBpbmp1cnkgcmlzaywgdGhlbiB0ZXN0IGNvbmZpcm0gdGhyZXNob2xkIGlzIHZhbHVhYmxlICsgaW50ZXJwcmV0DQphbGxfU0xKX2luY2lkZW50IDwtICBhbGxfU0xKX2luY2lkZW50ICU+JQ0KICBtdXRhdGUoYWJvdmVfdGhyZXNob2xkPWlmZWxzZShMYW5kaW5nLlJGRC4uTi5zLj49IDMxMDYxLjE2LCAxLDApKSNhZGQgbmV3Zm91bmQgdGhyZXNob2xkDQoNCiNEb2VzIGJlaW5nIGFib3ZlIHRoZSB0aHJlc2hvbGQgcmVsYXRlIHRvIGxvd2VyIGJvZHkgaW5qdXJ5IHJpc2s/DQptb2RlbCA8LSBnbG0oTEIuSW5qdXJ5fiBhYm92ZV90aHJlc2hvbGQsZGF0YT1hbGxfU0xKX2luY2lkZW50LCBmYW1pbHk9ImJpbm9taWFsIikNCnN1bW1hcnkobW9kZWwpDQpgYGANCg0KNC5NYXhpbXVtIENvbmNlbnRyaWMgUGVhayBGb3JjZQ0KYGBge3J9DQphbGxfU0xKX2luY2lkZW50JExCLkluanVyeSA8LSBhcy5mYWN0b3IoYWxsX1NMSl9pbmNpZGVudCRMQi5Jbmp1cnkpDQoNCmNwIDwtIGN1dHBvaW50cihhbGxfU0xKX2luY2lkZW50LCBNYXguQ29uY2VudHJpYy5QZWFrLkZvcmNlLi5OLiAsIExCLkluanVyeSwgbWV0aG9kPW1heGltaXplX21ldHJpYywgbWV0cmljPXlvdWRlbikNCnBsb3QoY3ApDQpzdW1tYXJ5KGNwKQ0KYGBgDQpGb3IgTWF4aW11bSBDb25jZW50cmljIFBlYWsgRm9yY2UgdGhlIG9wdGltYWwgY3V0cG9pbnQgaXMgMTI0My4zMTkgd2l0aCBhIEFVQyBvZiAwLjU0Niwgc2Vuc2l0aXZpdHkgb2YgMC44MTQ5IGFuZCBzcGVjaWZpY2l0eSBvZiAwLjM2MTEuDQoNCmBgYHtyfQ0KI1JPQyBvYmplY3QNCnJvY19vYmogPC0gcm9jKHJlc3BvbnNlID0gYWxsX1NMSl9pbmNpZGVudCRMQi5Jbmp1cnksDQogICAgICAgICAgICAgICBwcmVkaWN0b3IgPSBhbGxfU0xKX2luY2lkZW50JE1heC5Db25jZW50cmljLlBlYWsuRm9yY2UuLk4uICwgI3Bvd2VyDQogICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiPiIpICAjIHVzZSAiPCIgaWYgaGlnaGVyIHZhbHVlcz0gaGlnaCByaXNrIHByZWRpY3QgJ05vJw0KICAgICAgICAgICAgICAgIyBpZiA+IHJlbC4gY29uLiBwb3dlciB0aGVuIGxvd2VyIHJpc2sNCiNwbG90IGN1cnZlDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIC0gTWF4aW11bSBDb25jZW50cmljIFBlYWsgRm9yY2UiKQ0KYXVjX3ZhbHVlIDwtIGF1Yyhyb2Nfb2JqKQ0KcHJpbnQoYXVjX3ZhbHVlKQ0KYmVzdF9jb29yZHMgPC0gY29vcmRzKHJvY19vYmosICJiZXN0IiwgcmV0ID0gYygidGhyZXNob2xkIiwgInNlbnNpdGl2aXR5IiwgInNwZWNpZmljaXR5IiksIGJlc3QubWV0aG9kID0gInlvdWRlbiIpDQpiZXN0X2Nvb3Jkcw0KDQojcGxvdCArIHRocmVzaG9sZA0KcGxvdChyb2Nfb2JqLCBtYWluID0gIlJPQyBDdXJ2ZSB3aXRoIE9wdGltYWwgVGhyZXNob2xkIikNCmFibGluZShhID0gMCwgYiA9IDEsIGx0eSA9IDIsIGNvbCA9ICJncmF5IikNCnBvaW50cygxIC0gYmVzdF9jb29yZHNbInNwZWNpZmljaXR5Il0sIGJlc3RfY29vcmRzWyJzZW5zaXRpdml0eSJdLCBjb2wgPSAnI0NGQjg3QycsIHBjaCA9IDE5KQ0KdGV4dCgxIC0gYmVzdF9jb29yZHNbInNwZWNpZmljaXR5Il0sIGJlc3RfY29vcmRzWyJzZW5zaXRpdml0eSJdLA0KICAgICBsYWJlbHMgPSBwYXN0ZSgiVGhyZXNob2xkID0iLCByb3VuZChiZXN0X2Nvb3Jkc1sidGhyZXNob2xkIl0sIDIpKSwgcG9zID0gNCkNCmBgYA0KRm9yIE1heGltdW0gQ29uY2VudHJpYyBQZWFrIEZvcmNlIHRoZSBvcHRpbWFsIHRocmVzaG9sZCBpcyAxNjc4LjA5NCB3aXRoIGEgQVVDIG9mIDAuNDU0ICwgc2Vuc2l0aXZpdHkgb2YgMC44ODQzMTg4IGFuZCBzcGVjaWZpY2l0eSBvZiAwLjE5NDQ0NDQuICAgICANCg0KYGBge3J9DQojbG9vayBhdC9kaXNjb3Zlci9jcmVhdGUgbW9yZSBtZWFuaW5nZnVsIHRocmVzaG9sZHMgZm9yIHN0cmVuZ3RoIG1ldHJpY3MgcmVsYXRpbmcgdG8gTEIgaW5qdXJ5IHJpc2ssIHRoZW4gdGVzdCBjb25maXJtIHRocmVzaG9sZCBpcyB2YWx1YWJsZSArIGludGVycHJldA0KYWxsX1NMSl9pbmNpZGVudCA8LSAgYWxsX1NMSl9pbmNpZGVudCAlPiUNCiAgbXV0YXRlKGFib3ZlX3RocmVzaG9sZD1pZmVsc2UoTWF4LkNvbmNlbnRyaWMuUGVhay5Gb3JjZS4uTi4+PSAxMjQzLjMxOSwgMSwwKSkjYWRkIG5ld2ZvdW5kIHRocmVzaG9sZA0KDQojRG9lcyBiZWluZyBhYm92ZSB0aGUgdGhyZXNob2xkIHJlbGF0ZSB0byBsb3dlciBib2R5IGluanVyeSByaXNrPw0KbW9kZWwgPC0gZ2xtKExCLkluanVyeX4gYWJvdmVfdGhyZXNob2xkLGRhdGE9YWxsX1NMSl9pbmNpZGVudCwgZmFtaWx5PSJiaW5vbWlhbCIpDQpzdW1tYXJ5KG1vZGVsKQ0KYGBgDQoNCjUuQ29uY2VudHJpYyBJbXB1bHNlDQpgYGB7cn0NCmFsbF9TTEpfaW5jaWRlbnQkTEIuSW5qdXJ5IDwtIGFzLmZhY3RvcihhbGxfU0xKX2luY2lkZW50JExCLkluanVyeSkNCg0KY3AgPC0gY3V0cG9pbnRyKGFsbF9TTEpfaW5jaWRlbnQsIENvbmNlbnRyaWMuSW1wdWxzZS4uTnMuICwgTEIuSW5qdXJ5LCBtZXRob2Q9bWF4aW1pemVfbWV0cmljLCBtZXRyaWM9eW91ZGVuKQ0KcGxvdChjcCkNCnN1bW1hcnkoY3ApDQpgYGANCkZvciBDb25jZW50cmljIEltcHVsc2UgdGhlIG9wdGltYWwgY3V0cG9pbnQgaXMgMTIzLjEzNiB3aXRoIGEgQVVDIG9mIDAuNTIyNCwgc2Vuc2l0aXZpdHkgb2YgMC4xOTU0IGFuZCBzcGVjaWZpY2l0eSBvZiAwLjkzMDYuDQoNCmBgYHtyfQ0KI1JPQyBvYmplY3QNCnJvY19vYmogPC0gcm9jKHJlc3BvbnNlID0gYWxsX1NMSl9pbmNpZGVudCRMQi5Jbmp1cnksDQogICAgICAgICAgICAgICBwcmVkaWN0b3IgPSBhbGxfU0xKX2luY2lkZW50JENvbmNlbnRyaWMuSW1wdWxzZS4uTnMuICwgI3Bvd2VyDQogICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiPiIpICAjIHVzZSAiPCIgaWYgaGlnaGVyIHZhbHVlcz0gaGlnaCByaXNrIHByZWRpY3QgJ05vJw0KICAgICAgICAgICAgICAgIyBpZiA+IHJlbC4gY29uLiBwb3dlciB0aGVuIGxvd2VyIHJpc2sNCiNwbG90IGN1cnZlDQpwbG90KHJvY19vYmosIG1haW4gPSAiUk9DIEN1cnZlIC0gQ29uY2VudHJpYyBJbXB1bHNlIikNCmF1Y192YWx1ZSA8LSBhdWMocm9jX29iaikNCnByaW50KGF1Y192YWx1ZSkNCmJlc3RfY29vcmRzIDwtIGNvb3Jkcyhyb2Nfb2JqLCAiYmVzdCIsIHJldCA9IGMoInRocmVzaG9sZCIsICJzZW5zaXRpdml0eSIsICJzcGVjaWZpY2l0eSIpLCBiZXN0Lm1ldGhvZCA9ICJ5b3VkZW4iKQ0KYmVzdF9jb29yZHMNCg0KI3Bsb3QgKyB0aHJlc2hvbGQNCnBsb3Qocm9jX29iaiwgbWFpbiA9ICJST0MgQ3VydmUgd2l0aCBPcHRpbWFsIFRocmVzaG9sZCIpDQphYmxpbmUoYSA9IDAsIGIgPSAxLCBsdHkgPSAyLCBjb2wgPSAiZ3JheSIpDQpwb2ludHMoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwgY29sID0gJyNDRkI4N0MnLCBwY2ggPSAxOSkNCnRleHQoMSAtIGJlc3RfY29vcmRzWyJzcGVjaWZpY2l0eSJdLCBiZXN0X2Nvb3Jkc1sic2Vuc2l0aXZpdHkiXSwNCiAgICAgbGFiZWxzID0gcGFzdGUoIlRocmVzaG9sZCA9Iiwgcm91bmQoYmVzdF9jb29yZHNbInRocmVzaG9sZCJdLCAyKSksIHBvcyA9IDQpDQpgYGANCkZvciBDb25jZW50cmljIEltcHVsc2UgdGhlIG9wdGltYWwgdGhyZXNob2xkIGlzIDk0LjIwMzc1IHdpdGggYSBBVUMgb2YgMC40Nzc2ICwgc2Vuc2l0aXZpdHkgb2YgMC4xMjg1MzQ3IGFuZCBzcGVjaWZpY2l0eSBvZiAwLjkzMDU1NTYuICAgIDEyMy4xMzYNCg0KYGBge3J9DQojbG9vayBhdC9kaXNjb3Zlci9jcmVhdGUgbW9yZSBtZWFuaW5nZnVsIHRocmVzaG9sZHMgZm9yIHN0cmVuZ3RoIG1ldHJpY3MgcmVsYXRpbmcgdG8gTEIgaW5qdXJ5IHJpc2ssIHRoZW4gdGVzdCBjb25maXJtIHRocmVzaG9sZCBpcyB2YWx1YWJsZSArIGludGVycHJldA0KYWxsX1NMSl9pbmNpZGVudCA8LSAgYWxsX1NMSl9pbmNpZGVudCAlPiUNCiAgbXV0YXRlKGFib3ZlX3RocmVzaG9sZD1pZmVsc2UoQ29uY2VudHJpYy5JbXB1bHNlLi5Ocy4+PSAxMjMuMTM2LCAxLDApKSNhZGQgbmV3Zm91bmQgdGhyZXNob2xkDQoNCiNEb2VzIGJlaW5nIGFib3ZlIHRoZSB0aHJlc2hvbGQgcmVsYXRlIHRvIGxvd2VyIGJvZHkgaW5qdXJ5IHJpc2s/DQptb2RlbCA8LSBnbG0oTEIuSW5qdXJ5fiBhYm92ZV90aHJlc2hvbGQsZGF0YT1hbGxfU0xKX2luY2lkZW50LCBmYW1pbHk9ImJpbm9taWFsIikNCnN1bW1hcnkobW9kZWwpDQpgYGANCg0KDQoNCiMjIEFsbCBUaW1lDQoNCiMjIyAxLiBCYXNrZXRiYWxsIA0KYGBge3J9DQojY3JlYXRpbmcgbGlzdHMgb2YgYXRobGV0ZXMgdGhhdCBzdWZmZXJlZCBhbnkgbG93ZXIgYm9keSBpbmp1cmllcywgYWNsIGluanVyeSwgSFNJDQpsYl9pbmp1cnlfQiA8LSBpbmNpZGVudF9CICU+JQ0KICBmaWx0ZXIoTEIuSW5qdXJ5ID09IDEpICU+JQ0KICBkaXN0aW5jdChhbm9uX2lkKSAlPiUNCiAgcHVsbChhbm9uX2lkKQ0KYWNsX2luanVyeV9CIDwtIGluY2lkZW50X0IgJT4lDQogIGZpbHRlcihBQ0wgPT0gMSkgJT4lDQogIGRpc3RpbmN0KGFub25faWQpICU+JQ0KICBwdWxsKGFub25faWQpDQpoc2lfaW5qdXJ5X0IgPC0gaW5jaWRlbnRfQiAlPiUNCiAgZmlsdGVyKEhTSSA9PSAxKSAlPiUNCiAgZGlzdGluY3QoYW5vbl9pZCkgJT4lDQogIHB1bGwoYW5vbl9pZCkNCmBgYA0KDQpgYGB7cn0NCiNjcmVhdGluZyBuZXcgY29sdW1ucyBpbiB0aGUgbm9yZGljIHBlcmZvcm1hbmNlIGRhdGFzZXQgdGhhdCBhcmUgYmluYXJ5IGluZGljYXRvcnMgb2YgdGhlIGRpZmZlcmVudCBpbmp1cnkgZm9jdXNlcw0KcGVyZm9ybWFuY2VfQl9ub3JkaWNbJ0xCJ10gPC0gaWZlbHNlKHBlcmZvcm1hbmNlX0Jfbm9yZGljJGFub25faWQgJWluJSBsYl9pbmp1cnlfQiwgJ1llcycsICdObycpDQpwZXJmb3JtYW5jZV9CX25vcmRpY1snQUNMJ10gPC0gaWZlbHNlKHBlcmZvcm1hbmNlX0Jfbm9yZGljJGFub25faWQgJWluJSBhY2xfaW5qdXJ5X0IsICdZZXMnLCAnTm8nKQ0KcGVyZm9ybWFuY2VfQl9ub3JkaWNbJ0hTSSddIDwtIGlmZWxzZShwZXJmb3JtYW5jZV9CX25vcmRpYyRhbm9uX2lkICVpbiUgaHNpX2luanVyeV9CLCAnWWVzJywgJ05vJykNCg0KI3N1bW1hcmlzaW5nIHRoZSANCnBlcmZvcm1hbmNlX0Jfbm9yZGljICU+JQ0KICBncm91cF9ieShMQikgJT4lDQogIHN1bW1hcmlzZShBdmcuTWF4LkZvcmNlID0gbWVhbihNYXhpbXVtLkZvcmNlKSwNCiAgICAgICAgICAgIEF2Zy5JbWJhbGFuY2UgPSBtZWFuKE5vcmRpYy5NRUFOLkltYmFsYW5jZSksDQogICAgICAgICAgICBBdmcuUmVsLkZvcmNlID0gbWVhbihSZWxhdGl2ZS5NYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbikpDQpgYGANCg0KYGBge3J9DQojY3JlYXRpbmcgYSBib3hwbG90IGRpc3BsYXlpbmcgZGlzdHJpYnV0aW9uIG9mIHJlbGF0aXZlIG1heGltdW0gYmlsYXRlcmFsIG1lYW4gaW4gdGhvc2Ugd2hvIGV4cGVyaWVuY2VkIGxvd2VyIGJvZHkgaW5qdXJ5IHZzIHRob3NlIHRoYXQgZGlkIG5vdA0KZ2dwbG90KGRhdGEgPSBwZXJmb3JtYW5jZV9CX25vcmRpYyAlPiUgZmlsdGVyKFBvc2l0aW9uID09ICdGb3J3YXJkJyksIGFlcyh4ID0gTWF4aW11bS5Gb3JjZSwgeSA9IExCKSkgKyANCiAgZ2VvbV9ib3hwbG90KGZpbGwgPSAnI0NGQjg3QycsIGNvbG9yID0gJ2JsYWNrJykgKyANCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgTWF4aW11bSBGb3JjZSB2cyBMb3dlciBCb2R5IEluanVyeSAoQWxsIFRpbWUpJywNCiAgICAgICB5ID0gJ0RpZCBQbGF5ZXIgU3VmZmVyIExvd2VyIEJvZHkgSW5qdXJ5JywNCiAgICAgICB4ID0gJ01heGltdW0gRm9yY2UgKE4pJywNCiAgICAgICBjYXB0aW9uID0gJ1dvbWVucyBCYXNrZXRiYWxsIEZvcndhcmRzJykgKw0KICB0aGVtZV9idygpDQpgYGANCg0KYGBge3J9DQojY3JlYXRpbmcgbmV3IGNvbHVtbnMgaW4gdGhlIGltdHAgZGF0YXNldCB0aGF0IGFyZSBiaW5hcnkgaW5kaWNhdG9ycyBvZiB0aGUgZGlmZmVyZW50IGluanVyeSBmb2N1c2VzDQpJTVRQX0JbJ0xCJ10gPC0gaWZlbHNlKElNVFBfQiRhbm9uX2lkICVpbiUgbGJfaW5qdXJ5X0IsICdZZXMnLCAnTm8nKQ0KSU1UUF9CWydBQ0wnXSA8LSBpZmVsc2UoSU1UUF9CJGFub25faWQgJWluJSBhY2xfaW5qdXJ5X0IsICdZZXMnLCAnTm8nKQ0KSU1UUF9CWydIU0knXSA8LSBpZmVsc2UoSU1UUF9CJGFub25faWQgJWluJSBoc2lfaW5qdXJ5X0IsICdZZXMnLCAnTm8nKQ0KYGBgDQoNCmBgYHtyfQ0KI2NyZWF0aW5nIGEgYm94cGxvdCBkaXNwbGF5aW5nIGRpc3RyaWJ1dGlvbiBvZiBwZWFrIHZlcnRpY2FsIGZvcmNlIGFzeW1ldHJ5IGluIHRob3NlIHdobyBleHBlcmllbmNlZCBsb3dlciBib2R5IGluanVyeSB2cyB0aG9zZSB0aGF0IGRpZCBub3QNCmdncGxvdChkYXRhID0gSU1UUF9CLCBhZXMoeCA9IFBlYWsuVmVydGljYWwuRm9yY2UuLkFzeW0uLi5OLiwgZmlsbCA9IExCKSkgKyANCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC41KSArIA0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCcjQ0ZCODdDJywgJ2JsYWNrJykpICsgDQogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIEFic29sdXRlIEltcHVsc2UgYXQgMjAwIG1zIHZzIExvd2VyIEJvZHkgSW5qdXJ5IChBbGwgVGltZSknLA0KICAgICAgIHkgPSAnRGVuc2l0eScsDQogICAgICAgeCA9ICdBYnNvbHV0ZSBJbXB1bHNlIGF0IDIwMCBtcyAoTnMpJywNCiAgICAgICBmaWxsID0gJ0xvd2VyIEJvZHkgSW5qdXJ5JywNCiAgICAgICBjYXB0aW9uID0gJ1dvbWVucyBCYXNrZXRiYWxsJykgKw0KICB0aGVtZV9idygpDQpgYGANCg0KYGBge3J9DQojY3JlYXRpbmcgbmV3IGNvbHVtbnMgaW4gdGhlIGhqIGRhdGFzZXQgdGhhdCBhcmUgYmluYXJ5IGluZGljYXRvcnMgb2YgdGhlIGRpZmZlcmVudCBpbmp1cnkgZm9jdXNlcw0KSEpfQlsnTEInXSA8LSBpZmVsc2UoSEpfQiRhbm9uX2lkICVpbiUgbGJfaW5qdXJ5X0IsICdZZXMnLCAnTm8nKQ0KSEpfQlsnQUNMJ10gPC0gaWZlbHNlKEhKX0IkYW5vbl9pZCAlaW4lIGFjbF9pbmp1cnlfQiwgJ1llcycsICdObycpDQpISl9CWydIU0knXSA8LSBpZmVsc2UoSEpfQiRhbm9uX2lkICVpbiUgaHNpX2luanVyeV9CLCAnWWVzJywgJ05vJykNCmBgYA0KDQpgYGB7cn0NCiNjcmVhdGluZyBhIGJveHBsb3QgZGlzcGxheWluZyBkaXN0cmlidXRpb24gb2YgbWF4aW11bSBqdW1wIGhlaWdodCBpbiB0aG9zZSB3aG8gZXhwZXJpZW5jZWQgbG93ZXIgYm9keSBpbmp1cnkgdnMgdGhvc2UgdGhhdCBkaWQgbm90DQpnZ3Bsb3QoZGF0YSA9IGFsbF9ob3BqdW1wX2luY2lkZW50LCBhZXMoeCA9IE1heC5KdW1wLkhlaWdodC4uY20uLCBmaWxsID0gTEIuSW5qdXJ5KSkgKyANCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC41KSArIA0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCcjQ0ZCODdDJywgJ2JsYWNrJykpICsgDQogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIENvbnRhY3QgVGltZSB2cyBMb3dlciBCb2R5IEluanVyeSAoQWxsIFRpbWUpJywNCiAgICAgICB5ID0gJ0RlbnNpdHknLA0KICAgICAgIHggPSAnQmVzdCBDb250YWN0IFRpbWUgKG1zKScsDQogICAgICAgZmlsbCA9ICdMb3dlciBCb2R5IEluanVyeScsDQogICAgICAgY2FwdGlvbiA9ICdBbGwgV29tZW5zIFNwb3J0cycpICsNCiAgdGhlbWVfYncoKQ0KYGBgDQoNCiMjIyAyLiBTb2NjZXIgDQpgYGB7cn0NCiNjcmVhdGluZyBsaXN0cyBvZiBhdGhsZXRlcyB0aGF0IHN1ZmZlcmVkIGFueSBsb3dlciBib2R5IGluanVyaWVzLCBhY2wgaW5qdXJ5LCBIU0kNCmxiX2luanVyeV9TIDwtIGluY2lkZW50X1MgJT4lDQogIGZpbHRlcihMQi5Jbmp1cnkgPT0gMSkgJT4lDQogIGRpc3RpbmN0KGFub25faWQpICU+JQ0KICBwdWxsKGFub25faWQpDQphY2xfaW5qdXJ5X1MgPC0gaW5jaWRlbnRfUyAlPiUNCiAgZmlsdGVyKEFDTCA9PSAxKSAlPiUNCiAgZGlzdGluY3QoYW5vbl9pZCkgJT4lDQogIHB1bGwoYW5vbl9pZCkNCmhzaV9pbmp1cnlfUyA8LSBpbmNpZGVudF9TICU+JQ0KICBmaWx0ZXIoSFNJID09IDEpICU+JQ0KICBkaXN0aW5jdChhbm9uX2lkKSAlPiUNCiAgcHVsbChhbm9uX2lkKQ0KYGBgDQoNCmBgYHtyfQ0KI2NyZWF0aW5nIG5ldyBjb2x1bW5zIGluIHRoZSBub3JkaWMgcGVyZm9ybWFuY2UgZGF0YXNldCB0aGF0IGFyZSBiaW5hcnkgaW5kaWNhdG9ycyBvZiB0aGUgZGlmZmVyZW50IGluanVyeSBmb2N1c2VzDQpwZXJmb3JtYW5jZV9TX25vcmRpY1snTEInXSA8LSBpZmVsc2UocGVyZm9ybWFuY2VfU19ub3JkaWMkYW5vbl9pZCAlaW4lIGxiX2luanVyeV9TLCAnWWVzJywgJ05vJykNCnBlcmZvcm1hbmNlX1Nfbm9yZGljWydBQ0wnXSA8LSBpZmVsc2UocGVyZm9ybWFuY2VfU19ub3JkaWMkYW5vbl9pZCAlaW4lIGFjbF9pbmp1cnlfUywgJ1llcycsICdObycpDQpwZXJmb3JtYW5jZV9TX25vcmRpY1snSFNJJ10gPC0gaWZlbHNlKHBlcmZvcm1hbmNlX1Nfbm9yZGljJGFub25faWQgJWluJSBoc2lfaW5qdXJ5X1MsICdZZXMnLCAnTm8nKQ0KYGBgDQoNCmBgYHtyfQ0KI2NyZWF0aW5nIGEgYm94cGxvdCBkaXNwbGF5aW5nIGRpc3RyaWJ1dGlvbiBvZiByZWxhdGl2ZSBtYXhpbXVtIGJpbGF0ZXJhbCBtZWFuIGluIHRob3NlIHdobyBleHBlcmllbmNlZCBsb3dlciBib2R5IGluanVyeSB2cyB0aG9zZSB0aGF0IGRpZCBub3QNCmdncGxvdChwZXJmb3JtYW5jZV9TX25vcmRpYywgYWVzKHggPSBSZWxhdGl2ZS5NYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbiwgeSA9IExCKSkgKyANCiAgZ2VvbV9ib3hwbG90KGZpbGwgPSAnI0NGQjg3QycsIGNvbG9yID0gJ2JsYWNrJykgKyANCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgTWF4aW11bSBSZWxhdGl2ZSBCaWxhdGVyYWwgRm9yY2UgdnMgTG93ZXIgQm9keSBJbmp1cnknLA0KICAgICAgIHkgPSAnV2FzIHRoZSBQbGF5ZXIgSW5qdXJlZCcsDQogICAgICAgeCA9ICdNYXhpbXVtIFJlbGF0aXZlIEJpbGF0ZXJhbCBGb3JjZSAoTiAvIGtnKScpICsNCiAgdGhlbWVfYncoKQ0KYGBgDQoNCiMjIyAzLiBMYWNyb3NzZSANCg0KYGBge3J9DQojY3JlYXRpbmcgbGlzdHMgb2YgYXRobGV0ZXMgdGhhdCBzdWZmZXJlZCBhbnkgbG93ZXIgYm9keSBpbmp1cmllcywgYWNsIGluanVyeSwgSFNJDQpsYl9pbmp1cnlfTCA8LSBpbmNpZGVudF9MICU+JQ0KICBmaWx0ZXIoTEIuSW5qdXJ5ID09IDEpICU+JQ0KICBkaXN0aW5jdChhbm9uX2lkKSAlPiUNCiAgcHVsbChhbm9uX2lkKQ0KYWNsX2luanVyeV9MIDwtIGluY2lkZW50X0wgJT4lDQogIGZpbHRlcihBQ0wgPT0gMSkgJT4lDQogIGRpc3RpbmN0KGFub25faWQpICU+JQ0KICBwdWxsKGFub25faWQpDQpoc2lfaW5qdXJ5X0wgPC0gaW5jaWRlbnRfTCAlPiUNCiAgZmlsdGVyKEhTSSA9PSAxKSAlPiUNCiAgZGlzdGluY3QoYW5vbl9pZCkgJT4lDQogIHB1bGwoYW5vbl9pZCkNCmBgYA0KDQpgYGB7cn0NCiNjcmVhdGluZyBuZXcgY29sdW1ucyBpbiB0aGUgbm9yZGljIHBlcmZvcm1hbmNlIGRhdGFzZXQgdGhhdCBhcmUgYmluYXJ5IGluZGljYXRvcnMgb2YgdGhlIGRpZmZlcmVudCBpbmp1cnkgZm9jdXNlcw0KcGVyZm9ybWFuY2VfTF9ub3JkaWNbJ0xCJ10gPC0gaWZlbHNlKHBlcmZvcm1hbmNlX0xfbm9yZGljJGFub25faWQgJWluJSBsYl9pbmp1cnlfTCwgJ1llcycsICdObycpDQpwZXJmb3JtYW5jZV9MX25vcmRpY1snQUNMJ10gPC0gaWZlbHNlKHBlcmZvcm1hbmNlX0xfbm9yZGljJGFub25faWQgJWluJSBhY2xfaW5qdXJ5X0wsICdZZXMnLCAnTm8nKQ0KcGVyZm9ybWFuY2VfTF9ub3JkaWNbJ0hTSSddIDwtIGlmZWxzZShwZXJmb3JtYW5jZV9MX25vcmRpYyRhbm9uX2lkICVpbiUgaHNpX2luanVyeV9MLCAnWWVzJywgJ05vJykNCmBgYA0KDQpgYGB7cn0NCiNjcmVhdGluZyBhIGJveHBsb3QgZGlzcGxheWluZyBkaXN0cmlidXRpb24gb2YgcmVsYXRpdmUgbWF4aW11bSBiaWxhdGVyYWwgbWVhbiBpbiB0aG9zZSB3aG8gZXhwZXJpZW5jZWQgbG93ZXIgYm9keSBpbmp1cnkgdnMgdGhvc2UgdGhhdCBkaWQgbm90DQpnZ3Bsb3QocGVyZm9ybWFuY2VfTF9ub3JkaWMsIGFlcyh4ID0gUmVsYXRpdmUuTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4sIHkgPSBMQikpICsgDQogIGdlb21fYm94cGxvdChmaWxsID0gJyNDRkI4N0MnLCBjb2xvciA9ICdibGFjaycpICsgDQogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIE1heGltdW0gUmVsYXRpdmUgQmlsYXRlcmFsIEZvcmNlIHZzIExvd2VyIEJvZHkgSW5qdXJ5JywNCiAgICAgICB5ID0gJ1dhcyB0aGUgUGxheWVyIEluanVyZWQnLA0KICAgICAgIHggPSAnTWF4aW11bSBSZWxhdGl2ZSBCaWxhdGVyYWwgRm9yY2UgKE4gLyBrZyknKSArDQogIHRoZW1lX2J3KCkNCmBgYA0KDQojIyMgNC4gVm9sbGV5YmFsbCANCg0KYGBge3J9DQojY3JlYXRpbmcgbGlzdHMgb2YgYXRobGV0ZXMgdGhhdCBzdWZmZXJlZCBhbnkgbG93ZXIgYm9keSBpbmp1cmllcywgYWNsIGluanVyeSwgSFNJDQpsYl9pbmp1cnlfViA8LSBpbmNpZGVudF9WICU+JQ0KICBmaWx0ZXIoTEIuSW5qdXJ5ID09IDEpICU+JQ0KICBkaXN0aW5jdChhbm9uX2lkKSAlPiUNCiAgcHVsbChhbm9uX2lkKQ0KYWNsX2luanVyeV9WIDwtIGluY2lkZW50X1YgJT4lDQogIGZpbHRlcihBQ0wgPT0gMSkgJT4lDQogIGRpc3RpbmN0KGFub25faWQpICU+JQ0KICBwdWxsKGFub25faWQpDQpoc2lfaW5qdXJ5X1YgPC0gaW5jaWRlbnRfViAlPiUNCiAgZmlsdGVyKEhTSSA9PSAxKSAlPiUNCiAgZGlzdGluY3QoYW5vbl9pZCkgJT4lDQogIHB1bGwoYW5vbl9pZCkNCmBgYA0KDQpgYGB7cn0NCiNjcmVhdGluZyBuZXcgY29sdW1ucyBpbiB0aGUgbm9yZGljIHBlcmZvcm1hbmNlIGRhdGFzZXQgdGhhdCBhcmUgYmluYXJ5IGluZGljYXRvcnMgb2YgdGhlIGRpZmZlcmVudCBpbmp1cnkgZm9jdXNlcw0KcGVyZm9ybWFuY2VfVl9ub3JkaWNbJ0xCJ10gPC0gaWZlbHNlKHBlcmZvcm1hbmNlX1Zfbm9yZGljJGFub25faWQgJWluJSBsYl9pbmp1cnlfViwgJ1llcycsICdObycpDQpwZXJmb3JtYW5jZV9WX25vcmRpY1snQUNMJ10gPC0gaWZlbHNlKHBlcmZvcm1hbmNlX1Zfbm9yZGljJGFub25faWQgJWluJSBhY2xfaW5qdXJ5X1YsICdZZXMnLCAnTm8nKQ0KcGVyZm9ybWFuY2VfVl9ub3JkaWNbJ0hTSSddIDwtIGlmZWxzZShwZXJmb3JtYW5jZV9WX25vcmRpYyRhbm9uX2lkICVpbiUgaHNpX2luanVyeV9WLCAnWWVzJywgJ05vJykNCmBgYA0KDQpgYGB7cn0NCiNjcmVhdGluZyBhIGJveHBsb3QgZGlzcGxheWluZyBkaXN0cmlidXRpb24gb2YgcmVsYXRpdmUgbWF4aW11bSBiaWxhdGVyYWwgbWVhbiBpbiB0aG9zZSB3aG8gZXhwZXJpZW5jZWQgbG93ZXIgYm9keSBpbmp1cnkgdnMgdGhvc2UgdGhhdCBkaWQgbm90DQpnZ3Bsb3QocGVyZm9ybWFuY2VfVl9ub3JkaWMsIGFlcyh4ID0gUmVsYXRpdmUuTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4sIHkgPSBMQikpICsgDQogIGdlb21fYm94cGxvdChmaWxsID0gJyNDRkI4N0MnLCBjb2xvciA9ICdibGFjaycpICsgDQogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIE1heGltdW0gUmVsYXRpdmUgQmlsYXRlcmFsIEZvcmNlIHZzIExvd2VyIEJvZHkgSW5qdXJ5JywNCiAgICAgICB5ID0gJ1dhcyB0aGUgUGxheWVyIEluanVyZWQnLA0KICAgICAgIHggPSAnTWF4aW11bSBSZWxhdGl2ZSBCaWxhdGVyYWwgRm9yY2UgKE4gLyBrZyknKSArDQogIHRoZW1lX2J3KCkNCmBgYA0KDQoNCiMjIEluIFJlbGF0aW9uIHRvIEluanVyeSBUaW1lbGluZXMNCkxvb2tpbmcgNiBtb250aHMgaW4gdGhlIHBhc3QgbWF5IGJlIHdheSB0b28gbG9uZyBuZWVkIHRvIGZpZ3VyZSBvdXQgd2hhdCB3aW5kb3cgd29ya3MgYmVzdCBkZXBlbmRpbmcgb24gd2hpY2ggaW5qdXJpZXMuIEFsc28gd2FudCB0byBkaXNjdXNzIGlmIHdhbnQgdG8gZ3JvdXAgYnkgcGxheWVyIGFuZCBncm91cCBhbmQgY29uZGVuc2Ugb2JzZXJ2YXRpb25zIG9yIGp1c3QgbGVhdmUgb2JzZXJ2YXRpb25zIGFzIGlzLiANCg0KIyMjIDEuIEJhc2tldGJhbGwNCg0KYGBge3J9DQojc2VsZWN0cyB2YXJpYWJsZXMgb2YgaW50ZXJlc3QsIGZpbHRlcnMgZm9yIGxvd2VyIGJvZHkgaW5qdXJpZXMsIGFuZCBnZXRzIHJpZCBvZiBkdXBsaWNhdGUgb2JzZXJ2YXRpb25zDQppbmNpZF9iIDwtIEluY2lkZW50X0IgJT4lDQogIGZpbHRlcihCb2R5LlBhcnQgJWluJSBsb3dlcl9ib2R5KSAlPiUNCiAgZHBseXI6OnNlbGVjdCgiYW5vbl9pZCIsICJQb3NpdGlvbiIsICJEYXRlLm9mLkluanVyeS4uLk9uc2V0Lm9mLnN5bXB0b21zIiwgIlNpZGUiLCAiQm9keS5QYXJ0IiwgIlRpc3N1ZS5UeXBlIiwgIlBhdGhvbG9neS5UeXBlIiwgIk9TSUNTMTQuQ29kZSIsICJPU0lDUzEwLkNvZGUiLCAiT1NJQ1MxMC5EaWFnbm9zaXMiLCAiRmluYWwuRGlhZ25vc2lzIiwgIlJlY3VycmVuY2Uub2YuSW5qdXJ5IiwgIkluanVyeS5Qcm9nbm9zaXMiLCAiR2VuZXJhbC5NZWNoYW5pc20iLCAiU3BlY2lmaWMuTWVjaGFuaXNtIiwgIkZpbmFsRGlhZ25vc2lzSW5jaWRlbnREYXRlIiwgIlRvdGFsLlRpbWUuSW5qdXJlZCIsICJTZWFzb24uIiwgIkVuZC5EYXRlIiwgIlN0YXJ0Lm9mLlN0YXR1cyIpICU+JQ0KICBtdXRhdGUoU3RhcnQub2YuU3RhdHVzID0gYXMuRGF0ZShTdGFydC5vZi5TdGF0dXMsIGZvcm1hdCA9ICclbS8lZC8lWScpLA0KICAgICAgICAgRW5kLkRhdGUgPSBhcy5EYXRlKEVuZC5EYXRlLCBmb3JtYXQgPSAnJW0vJWQvJVknKSwNCiAgICAgICAgIFRpbWUgPSBhcy5udW1lcmljKEVuZC5EYXRlIC0gU3RhcnQub2YuU3RhdHVzKSkgJT4lDQogIGdyb3VwX2J5KGFub25faWQsIERhdGUub2YuSW5qdXJ5Li4uT25zZXQub2Yuc3ltcHRvbXMpICU+JQ0KICBtdXRhdGUoVG90YWwuVGltZS5Jbmp1cmVkID0gc3VtKFRvdGFsLlRpbWUuSW5qdXJlZCwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgIFRvdGFsLlRpbWUgPSBzdW0oVGltZSwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgIFNlYXNvbi4gPSBpZmVsc2UoU2Vhc29uLiA9PSAnUHJlLVNlYXNvbicgfCBTZWFzb24uID09ICdTdW1tZXIgV29ya291dHMnIHwgU2Vhc29uLiA9PSAnUG9zdC1TZWFzb24nLCAnT2ZmLVNlYXNvbicsIFNlYXNvbi4pLA0KICAgICAgICAgRGF0ZSA9IGFzLkRhdGUoRGF0ZS5vZi5Jbmp1cnkuLi5PbnNldC5vZi5zeW1wdG9tcywgZm9ybWF0ID0gJyVtLyVkLyVZJykpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIGRwbHlyOjpzZWxlY3QoLWMoJ0VuZC5EYXRlJywgJ1N0YXJ0Lm9mLlN0YXR1cycsICdUaW1lJykpICU+JQ0KICBncm91cF9ieShhY3Jvc3MoZXZlcnl0aGluZygpKSkgJT4lDQogIHN1bW1hcmlzZSguZ3JvdXBzID0gJ2Ryb3AnKQ0KYGBgDQoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9DQojY3JlYXRlcyBhIGRhdGFzZXQgZnJvbSB0aGUgaW5jaWRlbnQgcmVwb3J0IHRoYXQgc2VwYXJhdGVzIG91dCBhbGwgdGhlIGRhdGVzIGZvciBsb3dlciBib2R5IGluanVyaWVzIHRvIGNsYXNzaWZ5IG9ic2VydmF0aW9ucyBiYXNlZCBvbiB0aGVpciByZWxhdGlvbiB0byBsb3dlciBib2R5IGluanVyaWVzOiB3aXRoaW4gMyBtb250aHMgcHJpb3IgdG8gZmlyc3QgaW5qdXJ5LCBiZXR3ZWVuIGZpcnN0IGFuZCBzZWNvbmQgaW5qdXJ5LCBlY3QuDQpsYXN0X2luanVyeV9CIDwtIGluY2lkX2IgJT4lDQogIGFycmFuZ2UoRGF0ZSkgJT4lDQogIGdyb3VwX2J5KGFub25faWQpICU+JQ0KICBzdW1tYXJpemUoRGF0ZXMuRmluYWwgPSBwYXN0ZTAoRGF0ZSwgY29sbGFwc2UgPSAiIGFuZCAiKSwNCiAgICAgICAgICAgIE1lY2hhbmlzbSA9IHBhc3RlMChHZW5lcmFsLk1lY2hhbmlzbSwgY29sbGFwc2UgPSAiIGFuZCAiKSwNCiAgICAgICAgICAgIEluanVyeSA9IHBhc3RlMChGaW5hbC5EaWFnbm9zaXMsIGNvbGxhcHNlID0gIiBhbmQgIiksDQogICAgICAgICAgICBBcmVhID0gcGFzdGUwKEJvZHkuUGFydCwgY29sbGFwc2UgPSAiIGFuZCAiKSwNCiAgICAgICAgICAgIFRpbWUuSW5qdXJlZCA9IHBhc3RlMChUb3RhbC5UaW1lLkluanVyZWQsIGNvbGxhcHNlID0gIiBhbmQgIikpICU+JQ0KICBzZXBhcmF0ZShEYXRlcy5GaW5hbCwgYygnSW5qdXJ5LjEnLCAnSW5qdXJ5LjInLCAnSW5qdXJ5LjMnLCAnSW5qdXJ5LjQnKSwgc2VwID0gJyBhbmQgJykgJT4lDQogIG11dGF0ZShJbmp1cnkuMS5TdGFydCA9IGFzLkRhdGUoSW5qdXJ5LjEpIC0gbW9udGhzKDMpLA0KICAgICAgICAgSW5qdXJ5LjIuU3RhcnQgPSBpZmVsc2UoaXMubmEoSW5qdXJ5LjIpLCBOQSwgSW5qdXJ5LjEpLA0KICAgICAgICAgSW5qdXJ5LjMuU3RhcnQgPSBpZmVsc2UoaXMubmEoSW5qdXJ5LjMpLCBOQSwgSW5qdXJ5LjIpLA0KICAgICAgICAgSW5qdXJ5LjQuU3RhcnQgPSBpZmVsc2UoaXMubmEoSW5qdXJ5LjQpLCBOQSwgSW5qdXJ5LjMpKSAlPiUNCiAgc2VwYXJhdGUoTWVjaGFuaXNtLCBjKCdJbmp1cnkuMS5NZWNoJywgJ0luanVyeS4yLk1lY2gnLCAnSW5qdXJ5LjMuTWVjaCcsICdJbmp1cnkuNC5NZWNoJyksIHNlcCA9ICcgYW5kICcpICU+JQ0KICBzZXBhcmF0ZShJbmp1cnksIGMoJ0luanVyeS4xLkRpYWdub3NpcycsICdJbmp1cnkuMi5EaWFnbm9zaXMnLCAnSW5qdXJ5LjMuRGlhZ25vc2lzJywgJ0luanVyeS40LkRpYWdub3NpcycpLCBzZXAgPSAnIGFuZCAnKSAlPiUNCiAgc2VwYXJhdGUoVGltZS5Jbmp1cmVkLCBjKCdJbmp1cnkuMS5UaW1lJywgJ0luanVyeS4yLlRpbWUnLCAnSW5qdXJ5LjMuVGltZScsICdJbmp1cnkuNC5UaW1lJyksIHNlcCA9ICcgYW5kICcpICU+JQ0KICBzZXBhcmF0ZShBcmVhLCBjKCdJbmp1cnkuMS5BcmVhJywgJ0luanVyeS4yLkFyZWEnLCAnSW5qdXJ5LjMuQXJlYScsICdJbmp1cnkuNC5BcmVhJyksIHNlcCA9ICcgYW5kICcpDQpgYGANCg0KIyMjIyBQZXJmb3JtYW5jZSBEYXRhDQoNCioqTm9yZGljIERhdGEqKg0KDQpgYGB7cn0NCiNtZXJnZXMgdGhlIGxhc3RfaW5qdXJ5X0IgdG8gdGhlIHBlcmZvcm1hbmNlX0Jfbm9yZGljIGJ5IGFub25faWQNCm1lcmdlX3BlcmZvcm1hbmNlX0IgPC0gbWVyZ2UobGFzdF9pbmp1cnlfQiwgcGVyZm9ybWFuY2VfQl9ub3JkaWMsIGJ5ID0gYygnYW5vbl9pZCcpLCBhbGwgPSBUUlVFKQ0KDQojY3JlYXRlcyBhIHZhcmlhYmxlIGNhbGxlZCBHcm91cCB0aGF0IGdyb3VwcyBiYXNlZCBvbiBkYXRlIHdpdGhpbiBpbmp1cnkgaW50ZXJ2YWxzIGFuZCBvdXRwdXRzICdBZnRlcicgaWYgdGhlIGRhdGUgaXMgYWZ0ZXIgYWxsIGluanVyaWVzLCBhbmQgdGhlbiB0aGVzZSBhcmUgb21pdHRlZA0KbWVyZ2VfcGVyZm9ybWFuY2VfQiA8LSBtZXJnZV9wZXJmb3JtYW5jZV9CICU+JQ0KICBtdXRhdGUoVHJlbmQgPSBpZmVsc2UoVHJlbmQgPT0gJ05ldXRyYWwnLCAwLCBpZmVsc2UoVHJlbmQgPT0gJ1VwJywgMSwgLTEpKSwNCiAgICAgICAgIEdyb3VwID0gY2FzZV93aGVuKA0KICAgIGlzLm5hKEluanVyeS4xKSB8IERhdGUgPCBJbmp1cnkuMS5TdGFydCB+ICcwJywNCiAgICAhaXMubmEoSW5qdXJ5LjEpICYgRGF0ZSA+PSBJbmp1cnkuMS5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjEgfiAnMScsDQogICAgIWlzLm5hKEluanVyeS4yKSAmIERhdGUgPj0gSW5qdXJ5LjIuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4yIH4gJzInLA0KICAgICFpcy5uYShJbmp1cnkuMykgJiBEYXRlID49IEluanVyeS4zLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMyB+ICczJywNCiAgICAhaXMubmEoSW5qdXJ5LjQpICYgRGF0ZSA+PSBJbmp1cnkuNC5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjQgfiAnNCcsDQogICAgVFJVRSB+ICdBZnRlcicpKSAlPiUNCiAgZmlsdGVyKEdyb3VwICE9ICdBZnRlcicpDQoNCiNjb25kZW5zZXMgb2JzZXJ2YXRpb25zIGJhc2VkIG9uIGdyb3VwIGFuZCBwbGF5ZXIgc3VtbWFyaXppbmcgbWVhbnMgb2YgdmFyaWFibGVzIG9mIGludGVyZXN0DQptZXJnZV9wZXJmb3JtYW5jZV9CIDwtIG1lcmdlX3BlcmZvcm1hbmNlX0IgJT4lDQogIG11dGF0ZShJbmp1cnkgPSBjYXNlX3doZW4oDQogICAgR3JvdXAgPT0gMCB+ICdOb25lJywNCiAgICBHcm91cCA9PSAxIH4gSW5qdXJ5LjEuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDIgfiBJbmp1cnkuMi5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gMyB+IEluanVyeS4zLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA0IH4gSW5qdXJ5LjQuRGlhZ25vc2lzLA0KICAgIFRSVUUgfiAnQWZ0ZXInDQogICksDQogIEFyZWEgPSBjYXNlX3doZW4oDQogICAgR3JvdXAgPT0gMCB+ICdOb25lJywNCiAgICBHcm91cCA9PSAxIH4gSW5qdXJ5LjEuQXJlYSwNCiAgICBHcm91cCA9PSAyIH4gSW5qdXJ5LjIuQXJlYSwNCiAgICBHcm91cCA9PSAzIH4gSW5qdXJ5LjMuQXJlYSwNCiAgICBHcm91cCA9PSA0IH4gSW5qdXJ5LjQuQXJlYSwNCiAgICBUUlVFIH4gJ0FmdGVyJw0KICApKSAlPiUNCiAgbXV0YXRlKFdhcy5Jbmp1cmVkID0gaWZlbHNlKEdyb3VwID09IDEgfCBHcm91cCA9PSAyIHwgR3JvdXAgPT0gMywgJ1llcycsIEdyb3VwKSkgJT4lDQogIGRwbHlyOjpzZWxlY3QoYW5vbl9pZCwgRGF0ZSwgQXRobGV0ZS5Cb2R5d2VpZ2h0Li5rZy4sIE1heGltdW0uRm9yY2UsIEF2ZXJhZ2UuRm9yY2UsIEltcHVsc2UsIE5vcmRpYy5MZWZ0Lk1FQU4sIE5vcmRpYy5SaWdodC5NRUFOLCBOb3JkaWMuTUVBTi5JbWJhbGFuY2UsIE5vcmRpYy5MZWZ0Lk1BWCwgTm9yZGljLlJpZ2h0Lk1BWCwgTm9yZGljLk1BWC5JbWJhbGFuY2UsIFRyZW5kLCBOb3JkaWMuLi5EaWZmZXJlbmNlLmZyb20uRmlyc3QuVGVzdCwgTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4sIFJlbGF0aXZlLk1heGltdW0uTm9yZGljLkJpbGF0ZXJhbC5NZWFuLCBQb3NpdGlvbiwgU3BvcnQsIEluanVyeSwgQXJlYSwgV2FzLkluanVyZWQsIEZvcmNlLkRpZmYuTm9ybSwgSW1iYWxhbmNlLkRpZmYuTm9ybSkNCmBgYA0KDQoqKkhpcCBEYXRhKioNCg0KYGBge3J9DQojbWVyZ2VzIHRoZSBsYXN0X2luanVyeV9CIHRvIHRoZSBwZXJmb3JtYW5jZV9CX25vcmRpYyBieSBhbm9uX2lkDQptZXJnZV9oaXBfQiA8LSBtZXJnZShsYXN0X2luanVyeV9CLCBwZXJmb3JtYW5jZV9CX2hpcCwgYnkgPSBjKCdhbm9uX2lkJyksIGFsbCA9IFRSVUUpDQoNCiNjcmVhdGVzIGEgdmFyaWFibGUgY2FsbGVkIEdyb3VwIHRoYXQgZ3JvdXBzIGJhc2VkIG9uIGRhdGUgd2l0aGluIGluanVyeSBpbnRlcnZhbHMgYW5kIG91dHB1dHMgJ0FmdGVyJyBpZiB0aGUgZGF0ZSBpcyBhZnRlciBhbGwgaW5qdXJpZXMsIGFuZCB0aGVuIHRoZXNlIGFyZSBvbWl0dGVkDQptZXJnZV9oaXBfQiA8LSBtZXJnZV9oaXBfQiAlPiUNCiAgbXV0YXRlKEdyb3VwID0gY2FzZV93aGVuKA0KICAgIGlzLm5hKEluanVyeS4xKSB8IERhdGUgPCBJbmp1cnkuMS5TdGFydCB+ICcwJywNCiAgICAhaXMubmEoSW5qdXJ5LjEpICYgRGF0ZSA+PSBJbmp1cnkuMS5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjEgfiAnMScsDQogICAgIWlzLm5hKEluanVyeS4yKSAmIERhdGUgPj0gSW5qdXJ5LjIuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4yIH4gJzInLA0KICAgICFpcy5uYShJbmp1cnkuMykgJiBEYXRlID49IEluanVyeS4zLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMyB+ICczJywNCiAgICAhaXMubmEoSW5qdXJ5LjQpICYgRGF0ZSA+PSBJbmp1cnkuNC5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjQgfiAnNCcsDQogICAgVFJVRSB+ICdBZnRlcicpKSAlPiUNCiAgZmlsdGVyKEdyb3VwICE9ICdBZnRlcicpDQoNCiNjb25kZW5zZXMgb2JzZXJ2YXRpb25zIGJhc2VkIG9uIGdyb3VwIGFuZCBwbGF5ZXIgc3VtbWFyaXppbmcgbWVhbnMgb2YgdmFyaWFibGVzIG9mIGludGVyZXN0DQptZXJnZV9oaXBfQiA8LSBtZXJnZV9oaXBfQiAlPiUNCiAgbXV0YXRlKEluanVyeSA9IGNhc2Vfd2hlbigNCiAgICBHcm91cCA9PSAwIH4gJ05vbmUnLA0KICAgIEdyb3VwID09IDEgfiBJbmp1cnkuMS5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gMiB+IEluanVyeS4yLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSAzIH4gSW5qdXJ5LjMuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDQgfiBJbmp1cnkuNC5EaWFnbm9zaXMsDQogICAgVFJVRSB+ICdBZnRlcicNCiAgKSwNCiAgQXJlYSA9IGNhc2Vfd2hlbigNCiAgICBHcm91cCA9PSAwIH4gJ05vbmUnLA0KICAgIEdyb3VwID09IDEgfiBJbmp1cnkuMS5BcmVhLA0KICAgIEdyb3VwID09IDIgfiBJbmp1cnkuMi5BcmVhLA0KICAgIEdyb3VwID09IDMgfiBJbmp1cnkuMy5BcmVhLA0KICAgIEdyb3VwID09IDQgfiBJbmp1cnkuNC5BcmVhLA0KICAgIFRSVUUgfiAnQWZ0ZXInDQogICkpICU+JQ0KICBtdXRhdGUoV2FzLkluanVyZWQgPSBpZmVsc2UoR3JvdXAgPT0gMSB8IEdyb3VwID09IDIgfCBHcm91cCA9PSAzLCAnWWVzJywgR3JvdXApKSAlPiUNCiAgZHBseXI6OnNlbGVjdChhbm9uX2lkLCBEYXRlLCBBdGhsZXRlLkJvZHl3ZWlnaHQuLmtnLiwgTWF4aW11bS5Gb3JjZSwgQXZlcmFnZS5Gb3JjZSwgSW1wdWxzZSwgSGlwLkFiZC5MZWZ0Lk1FQU4sIEhpcC5BYmQuUmlnaHQuTUVBTiwgSGlwLkFiZHVjdGlvbi5NRUFOLkltYmFsYW5jZSwgSGlwLkFiZC5MZWZ0Lk1BWCwgSGlwLkFiZC5SaWdodC5NQVgsIEhpcC5BYmR1Y3Rpb24uTUFYLkltYmFsYW5jZSwgSGlwLkFkZC5MZWZ0Lk1FQU4sIEhpcC5BZGQuUmlnaHQuTUVBTiwgSGlwLkFkZHVjdGlvbi5NRUFOLkltYmFsYW5jZSwgSGlwLkFkZC5MZWZ0Lk1BWCwgSGlwLkFkZC5SaWdodC5NQVgsIEhpcC5BZGR1Y3Rpb24uTUFYLkltYmFsYW5jZSwgQmlsYXRlcmFsLkhpcC5BYmR1Y3Rpb24uQWRkdWN0aW9uLlJhdGlvLCBQb3NpdGlvbiwgU3BvcnQsIEluanVyeSwgQXJlYSwgV2FzLkluanVyZWQpDQpgYGANCg0KIyMjIyBOb3JkYm9yZCBEYXRhDQoNCioqQ01KIERhdGEqKg0KDQpgYGB7cn0NCiNtZXJnZXMgdGhlIGxhc3RfaW5qdXJ5X0IgdG8gdGhlIEhKX0IgYnkgYW5vbl9pZA0KbWVyZ2VfY21qX0IgPC0gbWVyZ2UobGFzdF9pbmp1cnlfQiwgYiwgYnkgPSBjKCdhbm9uX2lkJyksIGFsbCA9IFRSVUUpDQoNCiNjcmVhdGVzIGEgdmFyaWFibGUgY2FsbGVkIEdyb3VwIHRoYXQgZ3JvdXBzIGJhc2VkIG9uIGRhdGUgd2l0aGluIGluanVyeSBpbnRlcnZhbHMgYW5kIG91dHB1dHMgJ0FmdGVyJyBpZiB0aGUgZGF0ZSBpcyBhZnRlciBhbGwgaW5qdXJpZXMsIGFuZCB0aGVuIHRoZXNlIGFyZSBvbWl0dGVkDQptZXJnZV9jbWpfQiA8LSBtZXJnZV9jbWpfQiAlPiUNCiAgbXV0YXRlKEdyb3VwID0gY2FzZV93aGVuKA0KICAgIGlzLm5hKEluanVyeS4xKSB8IERhdGUgPCBJbmp1cnkuMS5TdGFydCB+ICcwJywNCiAgICAhaXMubmEoSW5qdXJ5LjEpICYgRGF0ZSA+PSBJbmp1cnkuMS5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjEgfiAnMScsDQogICAgIWlzLm5hKEluanVyeS4yKSAmIERhdGUgPj0gSW5qdXJ5LjIuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4yIH4gJzInLA0KICAgICFpcy5uYShJbmp1cnkuMykgJiBEYXRlID49IEluanVyeS4zLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMyB+ICczJywNCiAgICAhaXMubmEoSW5qdXJ5LjQpICYgRGF0ZSA+PSBJbmp1cnkuNC5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjQgfiAnNCcsDQogICAgVFJVRSB+ICdBZnRlcicpKSAlPiUNCiAgZmlsdGVyKEdyb3VwICE9ICdBZnRlcicpDQoNCiNjb25kZW5zZXMgb2JzZXJ2YXRpb25zIGJhc2VkIG9uIGdyb3VwIGFuZCBwbGF5ZXIgc3VtbWFyaXppbmcgbWVhbnMgb2YgdmFyaWFibGVzIG9mIGludGVyZXN0DQptZXJnZV9jbWpfQiA8LSBtZXJnZV9jbWpfQiAlPiUNCiAgbXV0YXRlKEluanVyeSA9IGNhc2Vfd2hlbigNCiAgICBHcm91cCA9PSAwIH4gJ05vbmUnLA0KICAgIEdyb3VwID09IDEgfiBJbmp1cnkuMS5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gMiB+IEluanVyeS4yLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSAzIH4gSW5qdXJ5LjMuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDQgfiBJbmp1cnkuNC5EaWFnbm9zaXMsDQogICAgVFJVRSB+ICdBZnRlcicNCiAgKSwNCiAgQXJlYSA9IGNhc2Vfd2hlbigNCiAgICBHcm91cCA9PSAwIH4gJ05vbmUnLA0KICAgIEdyb3VwID09IDEgfiBJbmp1cnkuMS5BcmVhLA0KICAgIEdyb3VwID09IDIgfiBJbmp1cnkuMi5BcmVhLA0KICAgIEdyb3VwID09IDMgfiBJbmp1cnkuMy5BcmVhLA0KICAgIEdyb3VwID09IDQgfiBJbmp1cnkuNC5BcmVhLA0KICAgIFRSVUUgfiAnQWZ0ZXInDQogICkpICU+JQ0KICBtdXRhdGUoV2FzLkluanVyZWQgPSBpZmVsc2UoR3JvdXAgPT0gMSB8IEdyb3VwID09IDIgfCBHcm91cCA9PSAzLCAnWWVzJywgR3JvdXApKSAlPiUNCiAgZHBseXI6OnNlbGVjdChhbm9uX2lkLCBEYXRlLCBDb3VudGVybW92ZW1lbnQuRGVwdGguLmNtLiwgUGVhay5Qb3dlci4uLkJNLi5XLmtnLiwgTGFuZGluZy5SRkQuLk4ucy4sIEVjY2VudHJpYy5Db25jZW50cmljLk1lYW4uRm9yY2UuUmF0aW8sIFBlYWsuTGFuZGluZy5Gb3JjZS4uQXN5bS4uLk4uLCBQZWFrLlBvd2VyLi5XLiwgQ29uY2VudHJpYy5SRkQuLk4ucy4sIEVjY2VudHJpYy5NZWFuLkJyYWtpbmcuRm9yY2UuLk4uLCBDb25jZW50cmljLlRpbWUudG8uUGVhay5Gb3JjZS4ucy4sIExhbmRpbmcuTmV0LlBlYWsuRm9yY2UuLi5CTS4uTi5rZy4sIFBlYWsuTmV0LlRha2VvZmYuRm9yY2UuLi5CTS4uTi5rZy4sIENvbmNlbnRyaWMuUlBELi4uQk0uLlcucy5rZy4sIEZvcmNlLmF0LlBlYWsuUG93ZXIuLk4uLCBFY2NlbnRyaWMuTWVhbi5EZWNlbGVyYXRpb24uRm9yY2UuLk4uLCBFY2NlbnRyaWMuUGVhay5Gb3JjZS4uTi4sIFJTSS5Nb2RpZmllZC4ubS5zLiwgQ01KLlN0aWZmbmVzcy4uTGVmdC4uLk4ubS4sIENNSi5TdGlmZm5lc3MuLlJpZ2h0Li4uTi5tLiwgRWNjZW50cmljLkFzeW1tZXRyeSwgQ29uY2VudHJpYy5Bc3ltbWV0cnksIFBlYWsuTGFuZGluZy5Bc3ltbWV0cnksIEluanVyeSwgQXJlYSwgV2FzLkluanVyZWQsIFNwb3J0LCBEU0ksIERTSS5CdWNrZXQpDQpgYGANCg0KKipISiBEYXRhKioNCg0KYGBge3J9DQojbWVyZ2VzIHRoZSBsYXN0X2luanVyeV9CIHRvIHRoZSBISl9CIGJ5IGFub25faWQNCm1lcmdlX2hqX0IgPC0gbWVyZ2UobGFzdF9pbmp1cnlfQiwgSEpfQiwgYnkgPSBjKCdhbm9uX2lkJyksIGFsbCA9IFRSVUUpDQoNCiNjcmVhdGVzIGEgdmFyaWFibGUgY2FsbGVkIEdyb3VwIHRoYXQgZ3JvdXBzIGJhc2VkIG9uIGRhdGUgd2l0aGluIGluanVyeSBpbnRlcnZhbHMgYW5kIG91dHB1dHMgJ0FmdGVyJyBpZiB0aGUgZGF0ZSBpcyBhZnRlciBhbGwgaW5qdXJpZXMsIGFuZCB0aGVuIHRoZXNlIGFyZSBvbWl0dGVkDQptZXJnZV9oal9CIDwtIG1lcmdlX2hqX0IgJT4lDQogIG11dGF0ZShHcm91cCA9IGNhc2Vfd2hlbigNCiAgICBpcy5uYShJbmp1cnkuMSkgfCBEYXRlIDwgSW5qdXJ5LjEuU3RhcnQgfiAnMCcsDQogICAgIWlzLm5hKEluanVyeS4xKSAmIERhdGUgPj0gSW5qdXJ5LjEuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4xIH4gJzEnLA0KICAgICFpcy5uYShJbmp1cnkuMikgJiBEYXRlID49IEluanVyeS4yLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMiB+ICcyJywNCiAgICAhaXMubmEoSW5qdXJ5LjMpICYgRGF0ZSA+PSBJbmp1cnkuMy5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjMgfiAnMycsDQogICAgIWlzLm5hKEluanVyeS40KSAmIERhdGUgPj0gSW5qdXJ5LjQuU3RhcnQgJiBEYXRlIDw9IEluanVyeS40IH4gJzQnLA0KICAgIFRSVUUgfiAnQWZ0ZXInKSkgJT4lDQogIGZpbHRlcihHcm91cCAhPSAnQWZ0ZXInKQ0KDQojY29uZGVuc2VzIG9ic2VydmF0aW9ucyBiYXNlZCBvbiBncm91cCBhbmQgcGxheWVyIHN1bW1hcml6aW5nIG1lYW5zIG9mIHZhcmlhYmxlcyBvZiBpbnRlcmVzdA0KbWVyZ2VfaGpfQiA8LSBtZXJnZV9oal9CICU+JQ0KICBtdXRhdGUoSW5qdXJ5ID0gY2FzZV93aGVuKA0KICAgIEdyb3VwID09IDAgfiAnTm9uZScsDQogICAgR3JvdXAgPT0gMSB+IEluanVyeS4xLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSAyIH4gSW5qdXJ5LjIuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDMgfiBJbmp1cnkuMy5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNCB+IEluanVyeS40LkRpYWdub3NpcywNCiAgICBUUlVFIH4gJ0FmdGVyJw0KICApLA0KICBBcmVhID0gY2FzZV93aGVuKA0KICAgIEdyb3VwID09IDAgfiAnTm9uZScsDQogICAgR3JvdXAgPT0gMSB+IEluanVyeS4xLkFyZWEsDQogICAgR3JvdXAgPT0gMiB+IEluanVyeS4yLkFyZWEsDQogICAgR3JvdXAgPT0gMyB+IEluanVyeS4zLkFyZWEsDQogICAgR3JvdXAgPT0gNCB+IEluanVyeS40LkFyZWEsDQogICAgVFJVRSB+ICdBZnRlcicNCiAgKSkgJT4lDQogIG11dGF0ZShXYXMuSW5qdXJlZCA9IGlmZWxzZShHcm91cCA9PSAxIHwgR3JvdXAgPT0gMiB8IEdyb3VwID09IDMsICdZZXMnLCBHcm91cCkpICU+JQ0KICBkcGx5cjo6c2VsZWN0KGFub25faWQsIERhdGUsIENvcnJlY3RlZC5TdGFuZGluZy5XZWlnaHQuLktnLiwgTWVhbi5SU0kuLkZsaWdodC5Db250YWN0LlRpbWUuLCBBY3RpdmUuU3RpZmZuZXNzLi5OLm0uLCBCZXN0LkF2ZXJhZ2UuRm9yY2UuLk4uLCBCZXN0LkF2ZXJhZ2UuRm9yY2UuLkFzeW0uLi5OLiwgQmVzdC5UaW1lLnRvLlBlYWsuRm9yY2UuLm1zLiwgQmVzdC5Db250YWN0LlRpbWUuLm1zLiwgQmVzdC5GbGlnaHQuVGltZS4ubXMuLCBCZXN0LkltcHVsc2UuLk4ucy4sIEJlc3QuUGVhay5Gb3JjZS4uTi4sIEJlc3QuUGVhay5Gb3JjZS4uQXN5bS4uLk4uLCBNZWFuLkF2ZXJhZ2UuRm9yY2UuLk4uLCBNZWFuLkF2ZXJhZ2UuRm9yY2UuLkFzeW0uLi5OLiwgTWVhbi5MYW5kaW5nLlJGRC4uTi5zLiwgTWVhbi5MYW5kaW5nLlJGRC4uQXN5bS4uLk4ucy4sIFN0aWZmbmVzcy5GYXRpZ3VlLi4uLiwgU3RpZmZuZXNzLkZhdGlndWUuLkFzeW0uLi4uLiwgTWF4Lkp1bXAuSGVpZ2h0Li5jbS4sIEluanVyeSwgQXJlYSwgV2FzLkluanVyZWQsIFNwb3J0LCBISi5SU0ksIE1lYW4uRmxpZ2h0LlRpbWUuLm1zLiwgTWVhbi5Db250YWN0LlRpbWUuLm1zLikNCmBgYA0KDQpOZWVkIHRvIGNoZWNrIGNvZGUsIG9ubHkgZmluZGluZyA0IG9ic2VydmF0aW9ucyBpbiB0aGUgMyBtb250aHMgcHJpb3IgdG8gYW4gaW5qdXJ5IGFuZCBvbmx5IG9uZSBwbGF5ZXIuIE9mIHRoZSAxNyB1bmlxdWUgcGxheWVycyB3aG8gc3VmZmVyZWQgbG93ZXIgYm9keSBpbmp1cnkgaW4gYmFza2V0YmFsbCBwbGF5ZXJzIG9ubHkgOCBhcmUgcmVwcmVzZW50ZWQgaW4gdGhlIEhKIGRhdGFzZXQuIEFsbCBpbmp1cmllcyB3aXRoIGV4Y2VwdGlvbiBvZiBJRF80MCBvY2N1ciBhdCBsZWFzdCAyNjUgZGF5cyBhZnRlciB0aGUgb2JzZXJ2YXRpb247IG5vdCB2ZXJ5IGhlbHBmdWwuICANCg0KKipJTVRQIERhdGEqKg0KDQpgYGB7cn0NCiNtZXJnZXMgdGhlIGxhc3RfaW5qdXJ5X0IgdG8gdGhlIEhKX0IgYnkgYW5vbl9pZA0KbWVyZ2VfaW10cF9CIDwtIG1lcmdlKGxhc3RfaW5qdXJ5X0IsIElNVFBfQiwgYnkgPSBjKCdhbm9uX2lkJyksIGFsbCA9IFRSVUUpDQoNCiNjcmVhdGVzIGEgdmFyaWFibGUgY2FsbGVkIEdyb3VwIHRoYXQgZ3JvdXBzIGJhc2VkIG9uIGRhdGUgd2l0aGluIGluanVyeSBpbnRlcnZhbHMgYW5kIG91dHB1dHMgJ0FmdGVyJyBpZiB0aGUgZGF0ZSBpcyBhZnRlciBhbGwgaW5qdXJpZXMsIGFuZCB0aGVuIHRoZXNlIGFyZSBvbWl0dGVkDQptZXJnZV9pbXRwX0IgPC0gbWVyZ2VfaW10cF9CICU+JQ0KICBtdXRhdGUoR3JvdXAgPSBjYXNlX3doZW4oDQogICAgaXMubmEoSW5qdXJ5LjEpIHwgRGF0ZSA8IEluanVyeS4xLlN0YXJ0IH4gJzAnLA0KICAgICFpcy5uYShJbmp1cnkuMSkgJiBEYXRlID49IEluanVyeS4xLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMSB+ICcxJywNCiAgICAhaXMubmEoSW5qdXJ5LjIpICYgRGF0ZSA+PSBJbmp1cnkuMi5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjIgfiAnMicsDQogICAgIWlzLm5hKEluanVyeS4zKSAmIERhdGUgPj0gSW5qdXJ5LjMuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4zIH4gJzMnLA0KICAgICFpcy5uYShJbmp1cnkuNCkgJiBEYXRlID49IEluanVyeS40LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNCB+ICc0JywNCiAgICBUUlVFIH4gJ0FmdGVyJykpICU+JQ0KICBmaWx0ZXIoR3JvdXAgIT0gJ0FmdGVyJykNCg0KI2NvbmRlbnNlcyBvYnNlcnZhdGlvbnMgYmFzZWQgb24gZ3JvdXAgYW5kIHBsYXllciBzdW1tYXJpemluZyBtZWFucyBvZiB2YXJpYWJsZXMgb2YgaW50ZXJlc3QNCm1lcmdlX2ltdHBfQiA8LSBtZXJnZV9pbXRwX0IgJT4lDQogIG11dGF0ZShJbmp1cnkgPSBjYXNlX3doZW4oDQogICAgR3JvdXAgPT0gMCB+ICdOb25lJywNCiAgICBHcm91cCA9PSAxIH4gSW5qdXJ5LjEuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDIgfiBJbmp1cnkuMi5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gMyB+IEluanVyeS4zLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA0IH4gSW5qdXJ5LjQuRGlhZ25vc2lzLA0KICAgIFRSVUUgfiAnQWZ0ZXInDQogICksDQogIEFyZWEgPSBjYXNlX3doZW4oDQogICAgR3JvdXAgPT0gMCB+ICdOb25lJywNCiAgICBHcm91cCA9PSAxIH4gSW5qdXJ5LjEuQXJlYSwNCiAgICBHcm91cCA9PSAyIH4gSW5qdXJ5LjIuQXJlYSwNCiAgICBHcm91cCA9PSAzIH4gSW5qdXJ5LjMuQXJlYSwNCiAgICBHcm91cCA9PSA0IH4gSW5qdXJ5LjQuQXJlYSwNCiAgICBUUlVFIH4gJ0FmdGVyJw0KICApKSAlPiUNCiAgbXV0YXRlKFdhcy5Jbmp1cmVkID0gaWZlbHNlKEdyb3VwID09IDEgfCBHcm91cCA9PSAyIHwgR3JvdXAgPT0gMywgJ1llcycsIEdyb3VwKSkgJT4lDQogIGRwbHlyOjpzZWxlY3QoYW5vbl9pZCwgRGF0ZSwgQmFzZWxpbmUuRm9yY2UuLk4uLCBCYXNlbGluZS5Gb3JjZS4uQXN5bS4uLk4uLCBQZWFrLlZlcnRpY2FsLkZvcmNlLi5OLiwgUGVhay5WZXJ0aWNhbC5Gb3JjZS4uLkJNLi5OLmtnLiwgUGVhay5WZXJ0aWNhbC5Gb3JjZS4uQXN5bS4uLk4uLCBSRkQuLi41MG1zLi5OLnMuLCBSRkQuLi41MG1zLi5Bc3ltLi4uTi5zLiwgUkZELi4uMTAwbXMuLk4ucy4sIFJGRC4uLjEwMG1zLi5Bc3ltLi4uTi5zLiwgUkZELi4uMTUwbXMuLk4ucy4sIFJGRC4uLjE1MG1zLi5Bc3ltLi4uTi5zLiwgUkZELi4uMjAwbXMuLk4ucy4sIFJGRC4uLjIwMG1zLi5Bc3ltLi4uTi5zLiwgTmV0LlBlYWsuVmVydGljYWwuRm9yY2UuLk4ucy4sIE5ldC5QZWFrLlZlcnRpY2FsLkZvcmNlLi5Bc3ltLi4uTi5zLiwgRm9yY2UuYXQuMjAwbXMuLi5CTS4uTi5rZy4sIEluanVyeSwgQXJlYSwgV2FzLkluanVyZWQsIFNwb3J0KQ0KYGBgDQoNCk9mIHRoZSAxNyB1bmlxdWUgcGxheWVycyB0byBzdWZmZXIgbG93ZXIgYm9keSBpbmp1cnksIG9ubHkgNyBhcmUgcmVwcmVzZW50ZWQgaW4gSU1UUCBkYXRhLiBBbGwgb2JzZXJ2YXRpb25zIG9jY3VyIGF0IGxlYXN0IDk5IGRheXMgcHJpb3IgdG8gaW5qdXJ5IHdpdGggb25seSAxMSB3aXRoaW4gMTgwIGRheXMuICANCg0KIyMjIDIuIFNvY2Nlcg0KDQpgYGB7cn0NCiNzZWxlY3RzIHZhcmlhYmxlcyBvZiBpbnRlcmVzdCwgZmlsdGVycyBmb3IgbG93ZXIgYm9keSBpbmp1cmllcywgYW5kIGdldHMgcmlkIG9mIGR1cGxpY2F0ZSBvYnNlcnZhdGlvbnMNCmluY2lkX3MgPC0gSW5jaWRlbnRfUyAlPiUNCiAgZmlsdGVyKEJvZHkuUGFydCAlaW4lIGxvd2VyX2JvZHkpICU+JQ0KICBkcGx5cjo6c2VsZWN0KCJhbm9uX2lkIiwgIlBvc2l0aW9uIiwgIkRhdGUub2YuSW5qdXJ5Li4uT25zZXQub2Yuc3ltcHRvbXMiLCAiU2lkZSIsICJCb2R5LlBhcnQiLCAiVGlzc3VlLlR5cGUiLCAiUGF0aG9sb2d5LlR5cGUiLCAiT1NJQ1MxNC5Db2RlIiwgIk9TSUNTMTAuQ29kZSIsICJPU0lDUzEwLkRpYWdub3NpcyIsICJGaW5hbC5EaWFnbm9zaXMiLCAiUmVjdXJyZW5jZS5vZi5Jbmp1cnkiLCAiSW5qdXJ5LlByb2dub3NpcyIsICJHZW5lcmFsLk1lY2hhbmlzbSIsICJTcGVjaWZpYy5NZWNoYW5pc20iLCAiRmluYWxEaWFnbm9zaXNJbmNpZGVudERhdGUiLCAiVG90YWwuVGltZS5Jbmp1cmVkIiwgIlNlYXNvbi4iKSAlPiUNCiAgZ3JvdXBfYnkoYW5vbl9pZCwgRGF0ZS5vZi5Jbmp1cnkuLi5PbnNldC5vZi5zeW1wdG9tcykgJT4lDQogIG11dGF0ZShUb3RhbC5UaW1lLkluanVyZWQgPSBzdW0oVG90YWwuVGltZS5Jbmp1cmVkLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgRGF0ZSA9IGFzLkRhdGUoRGF0ZS5vZi5Jbmp1cnkuLi5PbnNldC5vZi5zeW1wdG9tcywgZm9ybWF0ID0gJyVtLyVkLyVZJyksDQogICAgICAgICBTZWFzb24uID0gaWZlbHNlKFNlYXNvbi4gPT0gJ1ByZS1TZWFzb24nIHwgU2Vhc29uLiA9PSAnU3VtbWVyIFdvcmtvdXRzJyB8IFNlYXNvbi4gPT0gJ1Bvc3QtU2Vhc29uJywgJ09mZi1TZWFzb24nLCBTZWFzb24uKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgZ3JvdXBfYnkoYWNyb3NzKGV2ZXJ5dGhpbmcoKSkpICU+JQ0KICBzdW1tYXJpc2UoLmdyb3VwcyA9ICdkcm9wJykNCmBgYA0KDQpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQ0KI2NyZWF0ZXMgYSBkYXRhc2V0IGZyb20gdGhlIGluY2lkZW50IHJlcG9ydCB0aGF0IHNlcGFyYXRlcyBvdXQgYWxsIHRoZSBkYXRlcyBmb3IgbG93ZXIgYm9keSBpbmp1cmllcyB0byBjbGFzc2lmeSBvYnNlcnZhdGlvbnMgYmFzZWQgb24gdGhlaXIgcmVsYXRpb24gdG8gbG93ZXIgYm9keSBpbmp1cmllczogd2l0aGluIDMgbW9udGhzIHByaW9yIHRvIGZpcnN0IGluanVyeSwgYmV0d2VlbiBmaXJzdCBhbmQgc2Vjb25kIGluanVyeSwgZWN0Lg0KbGFzdF9pbmp1cnlfUyA8LSBpbmNpZF9zICU+JQ0KICBhcnJhbmdlKERhdGUpICU+JQ0KICBncm91cF9ieShhbm9uX2lkKSAlPiUNCiAgc3VtbWFyaXplKERhdGVzLkZpbmFsID0gcGFzdGUwKERhdGUsIGNvbGxhcHNlID0gIiBhbmQgIiksDQogICAgICAgICAgICBNZWNoYW5pc20gPSBwYXN0ZTAoR2VuZXJhbC5NZWNoYW5pc20sIGNvbGxhcHNlID0gIiBhbmQgIiksDQogICAgICAgICAgICBJbmp1cnkgPSBwYXN0ZTAoRmluYWwuRGlhZ25vc2lzLCBjb2xsYXBzZSA9ICIgYW5kICIpLA0KICAgICAgICAgICAgQXJlYSA9IHBhc3RlMChCb2R5LlBhcnQsIGNvbGxhcHNlID0gIiBhbmQgIiksDQogICAgICAgICAgICBUaW1lLkluanVyZWQgPSBwYXN0ZTAoVG90YWwuVGltZS5Jbmp1cmVkLCBjb2xsYXBzZSA9ICIgYW5kICIpKSAlPiUNCiAgc2VwYXJhdGUoRGF0ZXMuRmluYWwsIGMoJ0luanVyeS4xJywgJ0luanVyeS4yJywgJ0luanVyeS4zJywgJ0luanVyeS40JywgJ0luanVyeS41JywgJ0luanVyeS42JywgJ0luanVyeS43JyksIHNlcCA9ICcgYW5kICcpICU+JQ0KICBtdXRhdGUoSW5qdXJ5LjEuU3RhcnQgPSBhcy5EYXRlKEluanVyeS4xKSAtIG1vbnRocygzKSwNCiAgICAgICAgIEluanVyeS4yLlN0YXJ0ID0gaWZlbHNlKGlzLm5hKEluanVyeS4yKSwgTkEsIEluanVyeS4xKSwNCiAgICAgICAgIEluanVyeS4zLlN0YXJ0ID0gaWZlbHNlKGlzLm5hKEluanVyeS4zKSwgTkEsIEluanVyeS4yKSwNCiAgICAgICAgIEluanVyeS40LlN0YXJ0ID0gaWZlbHNlKGlzLm5hKEluanVyeS40KSwgTkEsIEluanVyeS4zKSwNCiAgICAgICAgIEluanVyeS41LlN0YXJ0ID0gaWZlbHNlKGlzLm5hKEluanVyeS40KSwgTkEsIEluanVyeS40KSwNCiAgICAgICAgIEluanVyeS42LlN0YXJ0ID0gaWZlbHNlKGlzLm5hKEluanVyeS40KSwgTkEsIEluanVyeS41KSwNCiAgICAgICAgIEluanVyeS43LlN0YXJ0ID0gaWZlbHNlKGlzLm5hKEluanVyeS40KSwgTkEsIEluanVyeS42KSkgJT4lDQogIHNlcGFyYXRlKE1lY2hhbmlzbSwgYygnSW5qdXJ5LjEuTWVjaCcsICdJbmp1cnkuMi5NZWNoJywgJ0luanVyeS4zLk1lY2gnLCAnSW5qdXJ5LjQuTWVjaCcsICdJbmp1cnkuNS5NZWNoJywgJ0luanVyeS42Lk1lY2gnLCAnSW5qdXJ5LjcuTWVjaCcpLCBzZXAgPSAnIGFuZCAnKSAlPiUNCiAgc2VwYXJhdGUoSW5qdXJ5LCBjKCdJbmp1cnkuMS5EaWFnbm9zaXMnLCAnSW5qdXJ5LjIuRGlhZ25vc2lzJywgJ0luanVyeS4zLkRpYWdub3NpcycsICdJbmp1cnkuNC5EaWFnbm9zaXMnLCAnSW5qdXJ5LjUuRGlhZ25vc2lzJywgJ0luanVyeS42LkRpYWdub3NpcycsICdJbmp1cnkuNy5EaWFnbm9zaXMnKSwgc2VwID0gJyBhbmQgJykgJT4lDQogIHNlcGFyYXRlKFRpbWUuSW5qdXJlZCwgYygnSW5qdXJ5LjEuVGltZScsICdJbmp1cnkuMi5UaW1lJywgJ0luanVyeS4zLlRpbWUnLCAnSW5qdXJ5LjQuVGltZScsICdJbmp1cnkuNS5UaW1lJywgJ0luanVyeS42LlRpbWUnLCAnSW5qdXJ5LjcuVGltZScpLCBzZXAgPSAnIGFuZCAnKSAlPiUNCiAgc2VwYXJhdGUoQXJlYSwgYygnSW5qdXJ5LjEuQXJlYScsICdJbmp1cnkuMi5BcmVhJywgJ0luanVyeS4zLkFyZWEnLCAnSW5qdXJ5LjQuQXJlYScsICdJbmp1cnkuNS5BcmVhJywgJ0luanVyeS42LkFyZWEnLCAnSW5qdXJ5LjcuQXJlYScpLCBzZXAgPSAnIGFuZCAnKQ0KYGBgDQoNCiMjIyMgUGVyZm9ybWFuY2UgRGF0YQ0KDQoqKk5vcmRpYyBEYXRhKioNCg0KYGBge3J9DQojbWVyZ2VzIHRoZSBsYXN0X2luanVyeV9TIHRvIHRoZSBwZXJmb3JtYW5jZV9TX25vcmRpYyBieSBhbm9uX2lkDQptZXJnZV9wZXJmb3JtYW5jZV9TIDwtIG1lcmdlKGxhc3RfaW5qdXJ5X1MsIHBlcmZvcm1hbmNlX1Nfbm9yZGljLCBieSA9IGMoJ2Fub25faWQnKSwgYWxsID0gVFJVRSkNCg0KI2NyZWF0ZXMgYSB2YXJpYWJsZSBjYWxsZWQgR3JvdXAgdGhhdCBncm91cHMgYmFzZWQgb24gZGF0ZSB3aXRoaW4gaW5qdXJ5IGludGVydmFscyBhbmQgb3V0cHV0cyAnQWZ0ZXInIGlmIHRoZSBkYXRlIGlzIGFmdGVyIGFsbCBpbmp1cmllcywgYW5kIHRoZW4gdGhlc2UgYXJlIG9taXR0ZWQNCm1lcmdlX3BlcmZvcm1hbmNlX1MgPC0gbWVyZ2VfcGVyZm9ybWFuY2VfUyAlPiUNCiAgbXV0YXRlKFRyZW5kID0gaWZlbHNlKFRyZW5kID09ICdOZXV0cmFsJywgMCwgaWZlbHNlKFRyZW5kID09ICdVcCcsIDEsIC0xKSksDQogICAgICAgICBHcm91cCA9IGNhc2Vfd2hlbigNCiAgICBpcy5uYShJbmp1cnkuMSkgfCBEYXRlIDwgSW5qdXJ5LjEuU3RhcnQgfiAnMCcsDQogICAgIWlzLm5hKEluanVyeS4xKSAmIERhdGUgPj0gSW5qdXJ5LjEuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4xIH4gJzEnLA0KICAgICFpcy5uYShJbmp1cnkuMikgJiBEYXRlID49IEluanVyeS4yLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMiB+ICcyJywNCiAgICAhaXMubmEoSW5qdXJ5LjMpICYgRGF0ZSA+PSBJbmp1cnkuMy5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjMgfiAnMycsDQogICAgIWlzLm5hKEluanVyeS40KSAmIERhdGUgPj0gSW5qdXJ5LjQuU3RhcnQgJiBEYXRlIDw9IEluanVyeS40IH4gJzQnLA0KICAgICFpcy5uYShJbmp1cnkuNSkgJiBEYXRlID49IEluanVyeS41LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNSB+ICc1JywNCiAgICAhaXMubmEoSW5qdXJ5LjYpICYgRGF0ZSA+PSBJbmp1cnkuNi5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjYgfiAnNicsDQogICAgIWlzLm5hKEluanVyeS43KSAmIERhdGUgPj0gSW5qdXJ5LjcuU3RhcnQgJiBEYXRlIDw9IEluanVyeS43IH4gJzcnLA0KICAgIFRSVUUgfiAnQWZ0ZXInKSkgJT4lDQogIGZpbHRlcihHcm91cCAhPSAnQWZ0ZXInKQ0KDQojY29uZGVuc2VzIG9ic2VydmF0aW9ucyBiYXNlZCBvbiBncm91cCBhbmQgcGxheWVyIHN1bW1hcml6aW5nIG1lYW5zIG9mIHZhcmlhYmxlcyBvZiBpbnRlcmVzdA0KbWVyZ2VfcGVyZm9ybWFuY2VfUyA8LSBtZXJnZV9wZXJmb3JtYW5jZV9TICU+JQ0KICBtdXRhdGUoSW5qdXJ5ID0gY2FzZV93aGVuKA0KICAgIEdyb3VwID09IDAgfiAnTm9uZScsDQogICAgR3JvdXAgPT0gMSB+IEluanVyeS4xLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSAyIH4gSW5qdXJ5LjIuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDMgfiBJbmp1cnkuMy5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNCB+IEluanVyeS40LkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA1IH4gSW5qdXJ5LjUuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDYgfiBJbmp1cnkuNi5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNyB+IEluanVyeS43LkRpYWdub3NpcywNCiAgICBUUlVFIH4gJ0FmdGVyJw0KICApLA0KICBBcmVhID0gY2FzZV93aGVuKA0KICAgIEdyb3VwID09IDAgfiAnTm9uZScsDQogICAgR3JvdXAgPT0gMSB+IEluanVyeS4xLkFyZWEsDQogICAgR3JvdXAgPT0gMiB+IEluanVyeS4yLkFyZWEsDQogICAgR3JvdXAgPT0gMyB+IEluanVyeS4zLkFyZWEsDQogICAgR3JvdXAgPT0gNCB+IEluanVyeS40LkFyZWEsDQogICAgR3JvdXAgPT0gNSB+IEluanVyeS41LkFyZWEsDQogICAgR3JvdXAgPT0gNiB+IEluanVyeS42LkFyZWEsDQogICAgR3JvdXAgPT0gNyB+IEluanVyeS43LkFyZWEsDQogICAgVFJVRSB+ICdBZnRlcicNCiAgKSkgJT4lDQogIG11dGF0ZShXYXMuSW5qdXJlZCA9IGlmZWxzZShHcm91cCA9PSAxIHwgR3JvdXAgPT0gMiB8IEdyb3VwID09IDMgfCBHcm91cCA9PSA0IHwgR3JvdXAgPT0gNSB8IEdyb3VwID09IDYgfCBHcm91cCA9PSA3LCAnWWVzJywgR3JvdXApKSAlPiUNCiAgZHBseXI6OnNlbGVjdChhbm9uX2lkLCBEYXRlLCBBdGhsZXRlLkJvZHl3ZWlnaHQuLmtnLiwgTWF4aW11bS5Gb3JjZSwgQXZlcmFnZS5Gb3JjZSwgSW1wdWxzZSwgTm9yZGljLkxlZnQuTUVBTiwgTm9yZGljLlJpZ2h0Lk1FQU4sIE5vcmRpYy5NRUFOLkltYmFsYW5jZSwgTm9yZGljLkxlZnQuTUFYLCBOb3JkaWMuUmlnaHQuTUFYLCBOb3JkaWMuTUFYLkltYmFsYW5jZSwgVHJlbmQsIE5vcmRpYy4uLkRpZmZlcmVuY2UuZnJvbS5GaXJzdC5UZXN0LCBNYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbiwgUmVsYXRpdmUuTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4sIFBvc2l0aW9uLCBTcG9ydCwgSW5qdXJ5LCBBcmVhLCBXYXMuSW5qdXJlZCwgRm9yY2UuRGlmZi5Ob3JtLCBJbWJhbGFuY2UuRGlmZi5Ob3JtKQ0KYGBgDQoNCioqSGlwIERhdGEqKg0KDQpgYGB7cn0NCiNtZXJnZXMgdGhlIGxhc3RfaW5qdXJ5X1MgdG8gdGhlIHBlcmZvcm1hbmNlX1Nfbm9yZGljIGJ5IGFub25faWQNCm1lcmdlX2hpcF9TIDwtIG1lcmdlKGxhc3RfaW5qdXJ5X1MsIHBlcmZvcm1hbmNlX1NfaGlwLCBieSA9IGMoJ2Fub25faWQnKSwgYWxsID0gVFJVRSkNCg0KI2NyZWF0ZXMgYSB2YXJpYWJsZSBjYWxsZWQgR3JvdXAgdGhhdCBncm91cHMgYmFzZWQgb24gZGF0ZSB3aXRoaW4gaW5qdXJ5IGludGVydmFscyBhbmQgb3V0cHV0cyAnQWZ0ZXInIGlmIHRoZSBkYXRlIGlzIGFmdGVyIGFsbCBpbmp1cmllcywgYW5kIHRoZW4gdGhlc2UgYXJlIG9taXR0ZWQNCm1lcmdlX2hpcF9TIDwtIG1lcmdlX2hpcF9TICU+JQ0KICBtdXRhdGUoR3JvdXAgPSBjYXNlX3doZW4oDQogICAgaXMubmEoSW5qdXJ5LjEpIHwgRGF0ZSA8IEluanVyeS4xLlN0YXJ0IH4gJzAnLA0KICAgICFpcy5uYShJbmp1cnkuMSkgJiBEYXRlID49IEluanVyeS4xLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMSB+ICcxJywNCiAgICAhaXMubmEoSW5qdXJ5LjIpICYgRGF0ZSA+PSBJbmp1cnkuMi5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjIgfiAnMicsDQogICAgIWlzLm5hKEluanVyeS4zKSAmIERhdGUgPj0gSW5qdXJ5LjMuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4zIH4gJzMnLA0KICAgICFpcy5uYShJbmp1cnkuNCkgJiBEYXRlID49IEluanVyeS40LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNCB+ICc0JywNCiAgICAhaXMubmEoSW5qdXJ5LjUpICYgRGF0ZSA+PSBJbmp1cnkuNS5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjUgfiAnNScsDQogICAgIWlzLm5hKEluanVyeS42KSAmIERhdGUgPj0gSW5qdXJ5LjYuU3RhcnQgJiBEYXRlIDw9IEluanVyeS42IH4gJzYnLA0KICAgICFpcy5uYShJbmp1cnkuNykgJiBEYXRlID49IEluanVyeS43LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNyB+ICc3JywNCiAgICBUUlVFIH4gJ0FmdGVyJykpICU+JQ0KICBmaWx0ZXIoR3JvdXAgIT0gJ0FmdGVyJykNCg0KI2NvbmRlbnNlcyBvYnNlcnZhdGlvbnMgYmFzZWQgb24gZ3JvdXAgYW5kIHBsYXllciBzdW1tYXJpemluZyBtZWFucyBvZiB2YXJpYWJsZXMgb2YgaW50ZXJlc3QNCm1lcmdlX2hpcF9TIDwtIG1lcmdlX2hpcF9TICU+JQ0KICBtdXRhdGUoSW5qdXJ5ID0gY2FzZV93aGVuKA0KICAgIEdyb3VwID09IDAgfiAnTm9uZScsDQogICAgR3JvdXAgPT0gMSB+IEluanVyeS4xLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSAyIH4gSW5qdXJ5LjIuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDMgfiBJbmp1cnkuMy5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNCB+IEluanVyeS40LkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA1IH4gSW5qdXJ5LjUuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDYgfiBJbmp1cnkuNi5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNyB+IEluanVyeS43LkRpYWdub3NpcywNCiAgICBUUlVFIH4gJ0FmdGVyJw0KICApLA0KICBBcmVhID0gY2FzZV93aGVuKA0KICAgIEdyb3VwID09IDAgfiAnTm9uZScsDQogICAgR3JvdXAgPT0gMSB+IEluanVyeS4xLkFyZWEsDQogICAgR3JvdXAgPT0gMiB+IEluanVyeS4yLkFyZWEsDQogICAgR3JvdXAgPT0gMyB+IEluanVyeS4zLkFyZWEsDQogICAgR3JvdXAgPT0gNCB+IEluanVyeS40LkFyZWEsDQogICAgR3JvdXAgPT0gNSB+IEluanVyeS41LkFyZWEsDQogICAgR3JvdXAgPT0gNiB+IEluanVyeS42LkFyZWEsDQogICAgR3JvdXAgPT0gNyB+IEluanVyeS43LkFyZWEsDQogICAgVFJVRSB+ICdBZnRlcicNCiAgKSkgJT4lDQogIG11dGF0ZShXYXMuSW5qdXJlZCA9IGlmZWxzZShHcm91cCA9PSAxIHwgR3JvdXAgPT0gMiB8IEdyb3VwID09IDMgfCBHcm91cCA9PSA0IHwgR3JvdXAgPT0gNSB8IEdyb3VwID09IDYgfCBHcm91cCA9PSA3LCAnWWVzJywgR3JvdXApKSAlPiUNCiAgZHBseXI6OnNlbGVjdChhbm9uX2lkLCBEYXRlLCBBdGhsZXRlLkJvZHl3ZWlnaHQuLmtnLiwgTWF4aW11bS5Gb3JjZSwgQXZlcmFnZS5Gb3JjZSwgSW1wdWxzZSwgSGlwLkFiZC5MZWZ0Lk1FQU4sIEhpcC5BYmQuUmlnaHQuTUVBTiwgSGlwLkFiZHVjdGlvbi5NRUFOLkltYmFsYW5jZSwgSGlwLkFiZC5MZWZ0Lk1BWCwgSGlwLkFiZC5SaWdodC5NQVgsIEhpcC5BYmR1Y3Rpb24uTUFYLkltYmFsYW5jZSwgSGlwLkFkZC5MZWZ0Lk1FQU4sIEhpcC5BZGQuUmlnaHQuTUVBTiwgSGlwLkFkZHVjdGlvbi5NRUFOLkltYmFsYW5jZSwgSGlwLkFkZC5MZWZ0Lk1BWCwgSGlwLkFkZC5SaWdodC5NQVgsIEhpcC5BZGR1Y3Rpb24uTUFYLkltYmFsYW5jZSwgQmlsYXRlcmFsLkhpcC5BYmR1Y3Rpb24uQWRkdWN0aW9uLlJhdGlvLCBQb3NpdGlvbiwgU3BvcnQsIEluanVyeSwgQXJlYSwgV2FzLkluanVyZWQpDQpgYGANCg0KIyMjIyBOb3JkYm9yZCBEYXRhDQoNCioqQ01KIERhdGEqKg0KDQpgYGB7cn0NCiNtZXJnZXMgdGhlIGxhc3RfaW5qdXJ5X0IgdG8gdGhlIEhKX0IgYnkgYW5vbl9pZA0KbWVyZ2VfY21qX1MgPC0gbWVyZ2UobGFzdF9pbmp1cnlfUywgcywgYnkgPSBjKCdhbm9uX2lkJyksIGFsbCA9IFRSVUUpDQoNCiNjcmVhdGVzIGEgdmFyaWFibGUgY2FsbGVkIEdyb3VwIHRoYXQgZ3JvdXBzIGJhc2VkIG9uIGRhdGUgd2l0aGluIGluanVyeSBpbnRlcnZhbHMgYW5kIG91dHB1dHMgJ0FmdGVyJyBpZiB0aGUgZGF0ZSBpcyBhZnRlciBhbGwgaW5qdXJpZXMsIGFuZCB0aGVuIHRoZXNlIGFyZSBvbWl0dGVkDQptZXJnZV9jbWpfUyA8LSBtZXJnZV9jbWpfUyAlPiUNCiAgbXV0YXRlKEdyb3VwID0gY2FzZV93aGVuKA0KICAgIGlzLm5hKEluanVyeS4xKSB8IERhdGUgPCBJbmp1cnkuMS5TdGFydCB+ICcwJywNCiAgICAhaXMubmEoSW5qdXJ5LjEpICYgRGF0ZSA+PSBJbmp1cnkuMS5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjEgfiAnMScsDQogICAgIWlzLm5hKEluanVyeS4yKSAmIERhdGUgPj0gSW5qdXJ5LjIuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4yIH4gJzInLA0KICAgICFpcy5uYShJbmp1cnkuMykgJiBEYXRlID49IEluanVyeS4zLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMyB+ICczJywNCiAgICAhaXMubmEoSW5qdXJ5LjQpICYgRGF0ZSA+PSBJbmp1cnkuNC5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjQgfiAnNCcsDQogICAgIWlzLm5hKEluanVyeS41KSAmIERhdGUgPj0gSW5qdXJ5LjUuU3RhcnQgJiBEYXRlIDw9IEluanVyeS41IH4gJzUnLA0KICAgICFpcy5uYShJbmp1cnkuNikgJiBEYXRlID49IEluanVyeS42LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNiB+ICc2JywNCiAgICAhaXMubmEoSW5qdXJ5LjcpICYgRGF0ZSA+PSBJbmp1cnkuNy5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjcgfiAnNycsDQogICAgVFJVRSB+ICdBZnRlcicpKSAlPiUNCiAgZmlsdGVyKEdyb3VwICE9ICdBZnRlcicpDQoNCiNjb25kZW5zZXMgb2JzZXJ2YXRpb25zIGJhc2VkIG9uIGdyb3VwIGFuZCBwbGF5ZXIgc3VtbWFyaXppbmcgbWVhbnMgb2YgdmFyaWFibGVzIG9mIGludGVyZXN0DQptZXJnZV9jbWpfUyA8LSBtZXJnZV9jbWpfUyAlPiUNCiAgbXV0YXRlKEluanVyeSA9IGNhc2Vfd2hlbigNCiAgICBHcm91cCA9PSAwIH4gJ05vbmUnLA0KICAgIEdyb3VwID09IDEgfiBJbmp1cnkuMS5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gMiB+IEluanVyeS4yLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSAzIH4gSW5qdXJ5LjMuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDQgfiBJbmp1cnkuNC5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNSB+IEluanVyeS41LkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA2IH4gSW5qdXJ5LjYuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDcgfiBJbmp1cnkuNy5EaWFnbm9zaXMsDQogICAgVFJVRSB+ICdBZnRlcicNCiAgKSwNCiAgQXJlYSA9IGNhc2Vfd2hlbigNCiAgICBHcm91cCA9PSAwIH4gJ05vbmUnLA0KICAgIEdyb3VwID09IDEgfiBJbmp1cnkuMS5BcmVhLA0KICAgIEdyb3VwID09IDIgfiBJbmp1cnkuMi5BcmVhLA0KICAgIEdyb3VwID09IDMgfiBJbmp1cnkuMy5BcmVhLA0KICAgIEdyb3VwID09IDQgfiBJbmp1cnkuNC5BcmVhLA0KICAgIEdyb3VwID09IDUgfiBJbmp1cnkuNS5BcmVhLA0KICAgIEdyb3VwID09IDYgfiBJbmp1cnkuNi5BcmVhLA0KICAgIEdyb3VwID09IDcgfiBJbmp1cnkuNy5BcmVhLA0KICAgIFRSVUUgfiAnQWZ0ZXInDQogICkpICU+JQ0KICBtdXRhdGUoV2FzLkluanVyZWQgPSBpZmVsc2UoR3JvdXAgPT0gMSB8IEdyb3VwID09IDIgfCBHcm91cCA9PSAzIHwgR3JvdXAgPT0gNCB8IEdyb3VwID09IDUgfCBHcm91cCA9PSA2IHwgR3JvdXAgPT0gNywgJ1llcycsIEdyb3VwKSkgJT4lDQogIGRwbHlyOjpzZWxlY3QoYW5vbl9pZCwgRGF0ZSwgQ291bnRlcm1vdmVtZW50LkRlcHRoLi5jbS4sIFBlYWsuUG93ZXIuLi5CTS4uVy5rZy4sIExhbmRpbmcuUkZELi5OLnMuLCBFY2NlbnRyaWMuQ29uY2VudHJpYy5NZWFuLkZvcmNlLlJhdGlvLCBQZWFrLkxhbmRpbmcuRm9yY2UuLkFzeW0uLi5OLiwgUGVhay5Qb3dlci4uVy4sIENvbmNlbnRyaWMuUkZELi5OLnMuLCBFY2NlbnRyaWMuTWVhbi5CcmFraW5nLkZvcmNlLi5OLiwgQ29uY2VudHJpYy5UaW1lLnRvLlBlYWsuRm9yY2UuLnMuLCBMYW5kaW5nLk5ldC5QZWFrLkZvcmNlLi4uQk0uLk4ua2cuLCBQZWFrLk5ldC5UYWtlb2ZmLkZvcmNlLi4uQk0uLk4ua2cuLCBDb25jZW50cmljLlJQRC4uLkJNLi5XLnMua2cuLCBGb3JjZS5hdC5QZWFrLlBvd2VyLi5OLiwgRWNjZW50cmljLk1lYW4uRGVjZWxlcmF0aW9uLkZvcmNlLi5OLiwgRWNjZW50cmljLlBlYWsuRm9yY2UuLk4uLCBSU0kuTW9kaWZpZWQuLm0ucy4sIENNSi5TdGlmZm5lc3MuLkxlZnQuLi5OLm0uLCBDTUouU3RpZmZuZXNzLi5SaWdodC4uLk4ubS4sIEVjY2VudHJpYy5Bc3ltbWV0cnksIENvbmNlbnRyaWMuQXN5bW1ldHJ5LCBQZWFrLkxhbmRpbmcuQXN5bW1ldHJ5LCBJbmp1cnksIEFyZWEsIFdhcy5Jbmp1cmVkLCBTcG9ydCwgRFNJLCBEU0kuQnVja2V0KQ0KYGBgDQoNCioqSEogRGF0YSoqDQoNCmBgYHtyfQ0KI21lcmdlcyB0aGUgbGFzdF9pbmp1cnlfQiB0byB0aGUgSEpfQiBieSBhbm9uX2lkDQptZXJnZV9oal9TIDwtIG1lcmdlKGxhc3RfaW5qdXJ5X1MsIEhKX1MsIGJ5ID0gYygnYW5vbl9pZCcpLCBhbGwgPSBUUlVFKQ0KDQojY3JlYXRlcyBhIHZhcmlhYmxlIGNhbGxlZCBHcm91cCB0aGF0IGdyb3VwcyBiYXNlZCBvbiBkYXRlIHdpdGhpbiBpbmp1cnkgaW50ZXJ2YWxzIGFuZCBvdXRwdXRzICdBZnRlcicgaWYgdGhlIGRhdGUgaXMgYWZ0ZXIgYWxsIGluanVyaWVzLCBhbmQgdGhlbiB0aGVzZSBhcmUgb21pdHRlZA0KbWVyZ2VfaGpfUyA8LSBtZXJnZV9oal9TICU+JQ0KICBtdXRhdGUoR3JvdXAgPSBjYXNlX3doZW4oDQogICAgaXMubmEoSW5qdXJ5LjEpIHwgRGF0ZSA8IEluanVyeS4xLlN0YXJ0IH4gJzAnLA0KICAgICFpcy5uYShJbmp1cnkuMSkgJiBEYXRlID49IEluanVyeS4xLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMSB+ICcxJywNCiAgICAhaXMubmEoSW5qdXJ5LjIpICYgRGF0ZSA+PSBJbmp1cnkuMi5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjIgfiAnMicsDQogICAgIWlzLm5hKEluanVyeS4zKSAmIERhdGUgPj0gSW5qdXJ5LjMuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4zIH4gJzMnLA0KICAgICFpcy5uYShJbmp1cnkuNCkgJiBEYXRlID49IEluanVyeS40LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNCB+ICc0JywNCiAgICAhaXMubmEoSW5qdXJ5LjUpICYgRGF0ZSA+PSBJbmp1cnkuNS5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjUgfiAnNScsDQogICAgIWlzLm5hKEluanVyeS42KSAmIERhdGUgPj0gSW5qdXJ5LjYuU3RhcnQgJiBEYXRlIDw9IEluanVyeS42IH4gJzYnLA0KICAgICFpcy5uYShJbmp1cnkuNykgJiBEYXRlID49IEluanVyeS43LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNyB+ICc3JywNCiAgICBUUlVFIH4gJ0FmdGVyJykpICU+JQ0KICBmaWx0ZXIoR3JvdXAgIT0gJ0FmdGVyJykNCg0KI2NvbmRlbnNlcyBvYnNlcnZhdGlvbnMgYmFzZWQgb24gZ3JvdXAgYW5kIHBsYXllciBzdW1tYXJpemluZyBtZWFucyBvZiB2YXJpYWJsZXMgb2YgaW50ZXJlc3QNCm1lcmdlX2hqX1MgPC0gbWVyZ2VfaGpfUyAlPiUNCiAgbXV0YXRlKEluanVyeSA9IGNhc2Vfd2hlbigNCiAgICBHcm91cCA9PSAwIH4gJ05vbmUnLA0KICAgIEdyb3VwID09IDEgfiBJbmp1cnkuMS5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gMiB+IEluanVyeS4yLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSAzIH4gSW5qdXJ5LjMuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDQgfiBJbmp1cnkuNC5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNSB+IEluanVyeS41LkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA2IH4gSW5qdXJ5LjYuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDcgfiBJbmp1cnkuNy5EaWFnbm9zaXMsDQogICAgVFJVRSB+ICdBZnRlcicNCiAgKSwNCiAgQXJlYSA9IGNhc2Vfd2hlbigNCiAgICBHcm91cCA9PSAwIH4gJ05vbmUnLA0KICAgIEdyb3VwID09IDEgfiBJbmp1cnkuMS5BcmVhLA0KICAgIEdyb3VwID09IDIgfiBJbmp1cnkuMi5BcmVhLA0KICAgIEdyb3VwID09IDMgfiBJbmp1cnkuMy5BcmVhLA0KICAgIEdyb3VwID09IDQgfiBJbmp1cnkuNC5BcmVhLA0KICAgIEdyb3VwID09IDUgfiBJbmp1cnkuNS5BcmVhLA0KICAgIEdyb3VwID09IDYgfiBJbmp1cnkuNi5BcmVhLA0KICAgIEdyb3VwID09IDcgfiBJbmp1cnkuNy5BcmVhLA0KICAgIFRSVUUgfiAnQWZ0ZXInDQogICkpICU+JQ0KICBtdXRhdGUoV2FzLkluanVyZWQgPSBpZmVsc2UoR3JvdXAgPT0gMSB8IEdyb3VwID09IDIgfCBHcm91cCA9PSAzIHwgR3JvdXAgPT0gNCB8IEdyb3VwID09IDUgfCBHcm91cCA9PSA2IHwgR3JvdXAgPT0gNywgJ1llcycsIEdyb3VwKSkgJT4lDQogIGRwbHlyOjpzZWxlY3QoYW5vbl9pZCwgRGF0ZSwgQ29ycmVjdGVkLlN0YW5kaW5nLldlaWdodC4uS2cuLCBNZWFuLlJTSS4uRmxpZ2h0LkNvbnRhY3QuVGltZS4sIEFjdGl2ZS5TdGlmZm5lc3MuLk4ubS4sIEJlc3QuQXZlcmFnZS5Gb3JjZS4uTi4sIEJlc3QuQXZlcmFnZS5Gb3JjZS4uQXN5bS4uLk4uLCBCZXN0LlRpbWUudG8uUGVhay5Gb3JjZS4ubXMuLCBCZXN0LkNvbnRhY3QuVGltZS4ubXMuLCBCZXN0LkZsaWdodC5UaW1lLi5tcy4sIEJlc3QuSW1wdWxzZS4uTi5zLiwgQmVzdC5QZWFrLkZvcmNlLi5OLiwgQmVzdC5QZWFrLkZvcmNlLi5Bc3ltLi4uTi4sIE1lYW4uQXZlcmFnZS5Gb3JjZS4uTi4sIE1lYW4uQXZlcmFnZS5Gb3JjZS4uQXN5bS4uLk4uLCBNZWFuLkxhbmRpbmcuUkZELi5OLnMuLCBNZWFuLkxhbmRpbmcuUkZELi5Bc3ltLi4uTi5zLiwgU3RpZmZuZXNzLkZhdGlndWUuLi4uLCBTdGlmZm5lc3MuRmF0aWd1ZS4uQXN5bS4uLi4uLCBNYXguSnVtcC5IZWlnaHQuLmNtLiwgSW5qdXJ5LCBBcmVhLCBXYXMuSW5qdXJlZCwgU3BvcnQsIEhKLlJTSSwgTWVhbi5GbGlnaHQuVGltZS4ubXMuLCBNZWFuLkNvbnRhY3QuVGltZS4ubXMuKQ0KYGBgDQoNCioqSU1UUCBEYXRhKioNCg0KYGBge3J9DQojbWVyZ2VzIHRoZSBsYXN0X2luanVyeV9CIHRvIHRoZSBISl9CIGJ5IGFub25faWQNCm1lcmdlX2ltdHBfUyA8LSBtZXJnZShsYXN0X2luanVyeV9TLCBJTVRQX1MsIGJ5ID0gYygnYW5vbl9pZCcpLCBhbGwgPSBUUlVFKQ0KDQojY3JlYXRlcyBhIHZhcmlhYmxlIGNhbGxlZCBHcm91cCB0aGF0IGdyb3VwcyBiYXNlZCBvbiBkYXRlIHdpdGhpbiBpbmp1cnkgaW50ZXJ2YWxzIGFuZCBvdXRwdXRzICdBZnRlcicgaWYgdGhlIGRhdGUgaXMgYWZ0ZXIgYWxsIGluanVyaWVzLCBhbmQgdGhlbiB0aGVzZSBhcmUgb21pdHRlZA0KbWVyZ2VfaW10cF9TIDwtIG1lcmdlX2ltdHBfUyAlPiUNCiAgbXV0YXRlKEdyb3VwID0gY2FzZV93aGVuKA0KICAgIGlzLm5hKEluanVyeS4xKSB8IERhdGUgPCBJbmp1cnkuMS5TdGFydCB+ICcwJywNCiAgICAhaXMubmEoSW5qdXJ5LjEpICYgRGF0ZSA+PSBJbmp1cnkuMS5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjEgfiAnMScsDQogICAgIWlzLm5hKEluanVyeS4yKSAmIERhdGUgPj0gSW5qdXJ5LjIuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4yIH4gJzInLA0KICAgICFpcy5uYShJbmp1cnkuMykgJiBEYXRlID49IEluanVyeS4zLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMyB+ICczJywNCiAgICAhaXMubmEoSW5qdXJ5LjQpICYgRGF0ZSA+PSBJbmp1cnkuNC5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjQgfiAnNCcsDQogICAgIWlzLm5hKEluanVyeS41KSAmIERhdGUgPj0gSW5qdXJ5LjUuU3RhcnQgJiBEYXRlIDw9IEluanVyeS41IH4gJzUnLA0KICAgICFpcy5uYShJbmp1cnkuNikgJiBEYXRlID49IEluanVyeS42LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNiB+ICc2JywNCiAgICAhaXMubmEoSW5qdXJ5LjcpICYgRGF0ZSA+PSBJbmp1cnkuNy5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjcgfiAnNycsDQogICAgVFJVRSB+ICdBZnRlcicpKSAlPiUNCiAgZmlsdGVyKEdyb3VwICE9ICdBZnRlcicpDQoNCiNjb25kZW5zZXMgb2JzZXJ2YXRpb25zIGJhc2VkIG9uIGdyb3VwIGFuZCBwbGF5ZXIgc3VtbWFyaXppbmcgbWVhbnMgb2YgdmFyaWFibGVzIG9mIGludGVyZXN0DQptZXJnZV9pbXRwX1MgPC0gbWVyZ2VfaW10cF9TICU+JQ0KICBtdXRhdGUoSW5qdXJ5ID0gY2FzZV93aGVuKA0KICAgIEdyb3VwID09IDAgfiAnTm9uZScsDQogICAgR3JvdXAgPT0gMSB+IEluanVyeS4xLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSAyIH4gSW5qdXJ5LjIuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDMgfiBJbmp1cnkuMy5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNCB+IEluanVyeS40LkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA1IH4gSW5qdXJ5LjUuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDYgfiBJbmp1cnkuNi5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNyB+IEluanVyeS43LkRpYWdub3NpcywNCiAgICBUUlVFIH4gJ0FmdGVyJw0KICApLA0KICBBcmVhID0gY2FzZV93aGVuKA0KICAgIEdyb3VwID09IDAgfiAnTm9uZScsDQogICAgR3JvdXAgPT0gMSB+IEluanVyeS4xLkFyZWEsDQogICAgR3JvdXAgPT0gMiB+IEluanVyeS4yLkFyZWEsDQogICAgR3JvdXAgPT0gMyB+IEluanVyeS4zLkFyZWEsDQogICAgR3JvdXAgPT0gNCB+IEluanVyeS40LkFyZWEsDQogICAgR3JvdXAgPT0gNSB+IEluanVyeS41LkFyZWEsDQogICAgR3JvdXAgPT0gNiB+IEluanVyeS42LkFyZWEsDQogICAgR3JvdXAgPT0gNyB+IEluanVyeS43LkFyZWEsDQogICAgVFJVRSB+ICdBZnRlcicNCiAgKSkgJT4lDQogIG11dGF0ZShXYXMuSW5qdXJlZCA9IGlmZWxzZShHcm91cCA9PSAxIHwgR3JvdXAgPT0gMiB8IEdyb3VwID09IDMgfCBHcm91cCA9PSA0IHwgR3JvdXAgPT0gNSB8IEdyb3VwID09IDYgfCBHcm91cCA9PSA3LCAnWWVzJywgR3JvdXApKSAlPiUNCiAgZHBseXI6OnNlbGVjdChhbm9uX2lkLCBEYXRlLCBCYXNlbGluZS5Gb3JjZS4uTi4sIEJhc2VsaW5lLkZvcmNlLi5Bc3ltLi4uTi4sIFBlYWsuVmVydGljYWwuRm9yY2UuLk4uLCBQZWFrLlZlcnRpY2FsLkZvcmNlLi4uQk0uLk4ua2cuLCBQZWFrLlZlcnRpY2FsLkZvcmNlLi5Bc3ltLi4uTi4sIFJGRC4uLjUwbXMuLk4ucy4sIFJGRC4uLjUwbXMuLkFzeW0uLi5OLnMuLCBSRkQuLi4xMDBtcy4uTi5zLiwgUkZELi4uMTAwbXMuLkFzeW0uLi5OLnMuLCBSRkQuLi4xNTBtcy4uTi5zLiwgUkZELi4uMTUwbXMuLkFzeW0uLi5OLnMuLCBSRkQuLi4yMDBtcy4uTi5zLiwgUkZELi4uMjAwbXMuLkFzeW0uLi5OLnMuLCBOZXQuUGVhay5WZXJ0aWNhbC5Gb3JjZS4uTi5zLiwgTmV0LlBlYWsuVmVydGljYWwuRm9yY2UuLkFzeW0uLi5OLnMuLCBGb3JjZS5hdC4yMDBtcy4uLkJNLi5OLmtnLiwgSW5qdXJ5LCBBcmVhLCBXYXMuSW5qdXJlZCwgU3BvcnQpDQpgYGANCg0KIyMjIDMuIExhY3Jvc3NlDQoNCmBgYHtyfQ0KI3NlbGVjdHMgdmFyaWFibGVzIG9mIGludGVyZXN0LCBmaWx0ZXJzIGZvciBsb3dlciBib2R5IGluanVyaWVzLCBhbmQgZ2V0cyByaWQgb2YgZHVwbGljYXRlIG9ic2VydmF0aW9ucw0KaW5jaWRfbCA8LSBJbmNpZGVudF9MICU+JQ0KICBmaWx0ZXIoQm9keS5QYXJ0ICVpbiUgbG93ZXJfYm9keSkgJT4lDQogIGRwbHlyOjpzZWxlY3QoImFub25faWQiLCAiUG9zaXRpb24iLCAiRGF0ZS5vZi5Jbmp1cnkuLi5PbnNldC5vZi5zeW1wdG9tcyIsICJTaWRlIiwgIkJvZHkuUGFydCIsICJUaXNzdWUuVHlwZSIsICJQYXRob2xvZ3kuVHlwZSIsICJPU0lDUzE0LkNvZGUiLCAiT1NJQ1MxMC5Db2RlIiwgIk9TSUNTMTAuRGlhZ25vc2lzIiwgIkZpbmFsLkRpYWdub3NpcyIsICJSZWN1cnJlbmNlLm9mLkluanVyeSIsICJJbmp1cnkuUHJvZ25vc2lzIiwgIkdlbmVyYWwuTWVjaGFuaXNtIiwgIlNwZWNpZmljLk1lY2hhbmlzbSIsICJGaW5hbERpYWdub3Npc0luY2lkZW50RGF0ZSIsICJUb3RhbC5UaW1lLkluanVyZWQiLCAiU2Vhc29uLiIpICU+JQ0KICBncm91cF9ieShhbm9uX2lkLCBEYXRlLm9mLkluanVyeS4uLk9uc2V0Lm9mLnN5bXB0b21zKSAlPiUNCiAgbXV0YXRlKFRvdGFsLlRpbWUuSW5qdXJlZCA9IHN1bShUb3RhbC5UaW1lLkluanVyZWQsIG5hLnJtID0gVFJVRSksDQogICAgICAgICBEYXRlID0gYXMuRGF0ZShEYXRlLm9mLkluanVyeS4uLk9uc2V0Lm9mLnN5bXB0b21zLCBmb3JtYXQgPSAnJW0vJWQvJVknKSwNCiAgICAgICAgIFNlYXNvbi4gPSBpZmVsc2UoU2Vhc29uLiA9PSAnUHJlLVNlYXNvbicgfCBTZWFzb24uID09ICdTdW1tZXIgV29ya291dHMnIHwgU2Vhc29uLiA9PSAnUG9zdC1TZWFzb24nLCAnT2ZmLVNlYXNvbicsIFNlYXNvbi4pKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBncm91cF9ieShhY3Jvc3MoZXZlcnl0aGluZygpKSkgJT4lDQogIHN1bW1hcmlzZSguZ3JvdXBzID0gJ2Ryb3AnKQ0KYGBgDQoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9DQojY3JlYXRlcyBhIGRhdGFzZXQgZnJvbSB0aGUgaW5jaWRlbnQgcmVwb3J0IHRoYXQgc2VwYXJhdGVzIG91dCBhbGwgdGhlIGRhdGVzIGZvciBsb3dlciBib2R5IGluanVyaWVzIHRvIGNsYXNzaWZ5IG9ic2VydmF0aW9ucyBiYXNlZCBvbiB0aGVpciByZWxhdGlvbiB0byBsb3dlciBib2R5IGluanVyaWVzOiB3aXRoaW4gMyBtb250aHMgcHJpb3IgdG8gZmlyc3QgaW5qdXJ5LCBiZXR3ZWVuIGZpcnN0IGFuZCBzZWNvbmQgaW5qdXJ5LCBlY3QuDQpsYXN0X2luanVyeV9MIDwtIGluY2lkX2wgJT4lDQogIGFycmFuZ2UoRGF0ZSkgJT4lDQogIGdyb3VwX2J5KGFub25faWQpICU+JQ0KICBzdW1tYXJpemUoRGF0ZXMuRmluYWwgPSBwYXN0ZTAoRGF0ZSwgY29sbGFwc2UgPSAiIGFuZCAiKSwNCiAgICAgICAgICAgIE1lY2hhbmlzbSA9IHBhc3RlMChHZW5lcmFsLk1lY2hhbmlzbSwgY29sbGFwc2UgPSAiIGFuZCAiKSwNCiAgICAgICAgICAgIEluanVyeSA9IHBhc3RlMChGaW5hbC5EaWFnbm9zaXMsIGNvbGxhcHNlID0gIiBhbmQgIiksDQogICAgICAgICAgICBBcmVhID0gcGFzdGUwKEJvZHkuUGFydCwgY29sbGFwc2UgPSAiIGFuZCAiKSwNCiAgICAgICAgICAgIFRpbWUuSW5qdXJlZCA9IHBhc3RlMChUb3RhbC5UaW1lLkluanVyZWQsIGNvbGxhcHNlID0gIiBhbmQgIikpICU+JQ0KICBzZXBhcmF0ZShEYXRlcy5GaW5hbCwgYygnSW5qdXJ5LjEnLCAnSW5qdXJ5LjInLCAnSW5qdXJ5LjMnLCAnSW5qdXJ5LjQnLCAnSW5qdXJ5LjUnLCAnSW5qdXJ5LjYnLCAnSW5qdXJ5LjcnKSwgc2VwID0gJyBhbmQgJykgJT4lDQogIG11dGF0ZShJbmp1cnkuMS5TdGFydCA9IGFzLkRhdGUoSW5qdXJ5LjEpIC0gbW9udGhzKDMpLA0KICAgICAgICAgSW5qdXJ5LjIuU3RhcnQgPSBpZmVsc2UoaXMubmEoSW5qdXJ5LjIpLCBOQSwgSW5qdXJ5LjEpLA0KICAgICAgICAgSW5qdXJ5LjMuU3RhcnQgPSBpZmVsc2UoaXMubmEoSW5qdXJ5LjMpLCBOQSwgSW5qdXJ5LjIpLA0KICAgICAgICAgSW5qdXJ5LjQuU3RhcnQgPSBpZmVsc2UoaXMubmEoSW5qdXJ5LjQpLCBOQSwgSW5qdXJ5LjMpLA0KICAgICAgICAgSW5qdXJ5LjUuU3RhcnQgPSBpZmVsc2UoaXMubmEoSW5qdXJ5LjQpLCBOQSwgSW5qdXJ5LjQpLA0KICAgICAgICAgSW5qdXJ5LjYuU3RhcnQgPSBpZmVsc2UoaXMubmEoSW5qdXJ5LjQpLCBOQSwgSW5qdXJ5LjUpLA0KICAgICAgICAgSW5qdXJ5LjcuU3RhcnQgPSBpZmVsc2UoaXMubmEoSW5qdXJ5LjQpLCBOQSwgSW5qdXJ5LjYpKSAlPiUNCiAgc2VwYXJhdGUoTWVjaGFuaXNtLCBjKCdJbmp1cnkuMS5NZWNoJywgJ0luanVyeS4yLk1lY2gnLCAnSW5qdXJ5LjMuTWVjaCcsICdJbmp1cnkuNC5NZWNoJywgJ0luanVyeS41Lk1lY2gnLCAnSW5qdXJ5LjYuTWVjaCcsICdJbmp1cnkuNy5NZWNoJyksIHNlcCA9ICcgYW5kICcpICU+JQ0KICBzZXBhcmF0ZShJbmp1cnksIGMoJ0luanVyeS4xLkRpYWdub3NpcycsICdJbmp1cnkuMi5EaWFnbm9zaXMnLCAnSW5qdXJ5LjMuRGlhZ25vc2lzJywgJ0luanVyeS40LkRpYWdub3NpcycsICdJbmp1cnkuNS5EaWFnbm9zaXMnLCAnSW5qdXJ5LjYuRGlhZ25vc2lzJywgJ0luanVyeS43LkRpYWdub3NpcycpLCBzZXAgPSAnIGFuZCAnKSAlPiUNCiAgc2VwYXJhdGUoVGltZS5Jbmp1cmVkLCBjKCdJbmp1cnkuMS5UaW1lJywgJ0luanVyeS4yLlRpbWUnLCAnSW5qdXJ5LjMuVGltZScsICdJbmp1cnkuNC5UaW1lJywgJ0luanVyeS41LlRpbWUnLCAnSW5qdXJ5LjYuVGltZScsICdJbmp1cnkuNy5UaW1lJyksIHNlcCA9ICcgYW5kICcpICU+JQ0KICBzZXBhcmF0ZShBcmVhLCBjKCdJbmp1cnkuMS5BcmVhJywgJ0luanVyeS4yLkFyZWEnLCAnSW5qdXJ5LjMuQXJlYScsICdJbmp1cnkuNC5BcmVhJywgJ0luanVyeS41LkFyZWEnLCAnSW5qdXJ5LjYuQXJlYScsICdJbmp1cnkuNy5BcmVhJyksIHNlcCA9ICcgYW5kICcpDQpgYGANCg0KIyMjIyBQZXJmb3JtYW5jZSBEYXRhDQoNCioqTm9yZGljIERhdGEqKg0KDQpgYGB7cn0NCiNtZXJnZXMgdGhlIGxhc3RfaW5qdXJ5X1MgdG8gdGhlIHBlcmZvcm1hbmNlX1Nfbm9yZGljIGJ5IGFub25faWQNCm1lcmdlX3BlcmZvcm1hbmNlX0wgPC0gbWVyZ2UobGFzdF9pbmp1cnlfTCwgcGVyZm9ybWFuY2VfTF9ub3JkaWMsIGJ5ID0gYygnYW5vbl9pZCcpLCBhbGwgPSBUUlVFKQ0KDQojY3JlYXRlcyBhIHZhcmlhYmxlIGNhbGxlZCBHcm91cCB0aGF0IGdyb3VwcyBiYXNlZCBvbiBkYXRlIHdpdGhpbiBpbmp1cnkgaW50ZXJ2YWxzIGFuZCBvdXRwdXRzICdBZnRlcicgaWYgdGhlIGRhdGUgaXMgYWZ0ZXIgYWxsIGluanVyaWVzLCBhbmQgdGhlbiB0aGVzZSBhcmUgb21pdHRlZA0KbWVyZ2VfcGVyZm9ybWFuY2VfTCA8LSBtZXJnZV9wZXJmb3JtYW5jZV9MICU+JQ0KICBtdXRhdGUoVHJlbmQgPSBpZmVsc2UoVHJlbmQgPT0gJ05ldXRyYWwnLCAwLCBpZmVsc2UoVHJlbmQgPT0gJ1VwJywgMSwgLTEpKSwNCiAgICAgICAgIEdyb3VwID0gY2FzZV93aGVuKA0KICAgIGlzLm5hKEluanVyeS4xKSB8IERhdGUgPCBJbmp1cnkuMS5TdGFydCB+ICcwJywNCiAgICAhaXMubmEoSW5qdXJ5LjEpICYgRGF0ZSA+PSBJbmp1cnkuMS5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjEgfiAnMScsDQogICAgIWlzLm5hKEluanVyeS4yKSAmIERhdGUgPj0gSW5qdXJ5LjIuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4yIH4gJzInLA0KICAgICFpcy5uYShJbmp1cnkuMykgJiBEYXRlID49IEluanVyeS4zLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMyB+ICczJywNCiAgICAhaXMubmEoSW5qdXJ5LjQpICYgRGF0ZSA+PSBJbmp1cnkuNC5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjQgfiAnNCcsDQogICAgIWlzLm5hKEluanVyeS41KSAmIERhdGUgPj0gSW5qdXJ5LjUuU3RhcnQgJiBEYXRlIDw9IEluanVyeS41IH4gJzUnLA0KICAgICFpcy5uYShJbmp1cnkuNikgJiBEYXRlID49IEluanVyeS42LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNiB+ICc2JywNCiAgICAhaXMubmEoSW5qdXJ5LjcpICYgRGF0ZSA+PSBJbmp1cnkuNy5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjcgfiAnNycsDQogICAgVFJVRSB+ICdBZnRlcicpKSAlPiUNCiAgZmlsdGVyKEdyb3VwICE9ICdBZnRlcicpDQoNCiNjb25kZW5zZXMgb2JzZXJ2YXRpb25zIGJhc2VkIG9uIGdyb3VwIGFuZCBwbGF5ZXIgc3VtbWFyaXppbmcgbWVhbnMgb2YgdmFyaWFibGVzIG9mIGludGVyZXN0DQptZXJnZV9wZXJmb3JtYW5jZV9MIDwtIG1lcmdlX3BlcmZvcm1hbmNlX0wgJT4lDQogIG11dGF0ZShJbmp1cnkgPSBjYXNlX3doZW4oDQogICAgR3JvdXAgPT0gMCB+ICdOb25lJywNCiAgICBHcm91cCA9PSAxIH4gSW5qdXJ5LjEuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDIgfiBJbmp1cnkuMi5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gMyB+IEluanVyeS4zLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA0IH4gSW5qdXJ5LjQuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDUgfiBJbmp1cnkuNS5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNiB+IEluanVyeS42LkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA3IH4gSW5qdXJ5LjcuRGlhZ25vc2lzLA0KICAgIFRSVUUgfiAnQWZ0ZXInDQogICksDQogIEFyZWEgPSBjYXNlX3doZW4oDQogICAgR3JvdXAgPT0gMCB+ICdOb25lJywNCiAgICBHcm91cCA9PSAxIH4gSW5qdXJ5LjEuQXJlYSwNCiAgICBHcm91cCA9PSAyIH4gSW5qdXJ5LjIuQXJlYSwNCiAgICBHcm91cCA9PSAzIH4gSW5qdXJ5LjMuQXJlYSwNCiAgICBHcm91cCA9PSA0IH4gSW5qdXJ5LjQuQXJlYSwNCiAgICBHcm91cCA9PSA1IH4gSW5qdXJ5LjUuQXJlYSwNCiAgICBHcm91cCA9PSA2IH4gSW5qdXJ5LjYuQXJlYSwNCiAgICBHcm91cCA9PSA3IH4gSW5qdXJ5LjcuQXJlYSwNCiAgICBUUlVFIH4gJ0FmdGVyJw0KICApKSAlPiUNCiAgbXV0YXRlKFdhcy5Jbmp1cmVkID0gaWZlbHNlKEdyb3VwID09IDEgfCBHcm91cCA9PSAyIHwgR3JvdXAgPT0gMyB8IEdyb3VwID09IDQgfCBHcm91cCA9PSA1IHwgR3JvdXAgPT0gNiB8IEdyb3VwID09IDcsICdZZXMnLCBHcm91cCkpICU+JQ0KICBkcGx5cjo6c2VsZWN0KGFub25faWQsIERhdGUsIEF0aGxldGUuQm9keXdlaWdodC4ua2cuLCBNYXhpbXVtLkZvcmNlLCBBdmVyYWdlLkZvcmNlLCBJbXB1bHNlLCBOb3JkaWMuTGVmdC5NRUFOLCBOb3JkaWMuUmlnaHQuTUVBTiwgTm9yZGljLk1FQU4uSW1iYWxhbmNlLCBOb3JkaWMuTGVmdC5NQVgsIE5vcmRpYy5SaWdodC5NQVgsIE5vcmRpYy5NQVguSW1iYWxhbmNlLCBUcmVuZCwgTm9yZGljLi4uRGlmZmVyZW5jZS5mcm9tLkZpcnN0LlRlc3QsIE1heGltdW0uTm9yZGljLkJpbGF0ZXJhbC5NZWFuLCBSZWxhdGl2ZS5NYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbiwgUG9zaXRpb24sIFNwb3J0LCBJbmp1cnksIEFyZWEsIFdhcy5Jbmp1cmVkLCBGb3JjZS5EaWZmLk5vcm0sIEltYmFsYW5jZS5EaWZmLk5vcm0pDQpgYGANCg0KKipIaXAgRGF0YSoqDQoNCmBgYHtyfQ0KI21lcmdlcyB0aGUgbGFzdF9pbmp1cnlfTCB0byB0aGUgcGVyZm9ybWFuY2VfTF9ub3JkaWMgYnkgYW5vbl9pZA0KbWVyZ2VfaGlwX0wgPC0gbWVyZ2UobGFzdF9pbmp1cnlfTCwgcGVyZm9ybWFuY2VfTF9oaXAsIGJ5ID0gYygnYW5vbl9pZCcpLCBhbGwgPSBUUlVFKQ0KDQojY3JlYXRlcyBhIHZhcmlhYmxlIGNhbGxlZCBHcm91cCB0aGF0IGdyb3VwcyBiYXNlZCBvbiBkYXRlIHdpdGhpbiBpbmp1cnkgaW50ZXJ2YWxzIGFuZCBvdXRwdXRzICdBZnRlcicgaWYgdGhlIGRhdGUgaXMgYWZ0ZXIgYWxsIGluanVyaWVzLCBhbmQgdGhlbiB0aGVzZSBhcmUgb21pdHRlZA0KbWVyZ2VfaGlwX0wgPC0gbWVyZ2VfaGlwX0wgJT4lDQogIG11dGF0ZShHcm91cCA9IGNhc2Vfd2hlbigNCiAgICBpcy5uYShJbmp1cnkuMSkgfCBEYXRlIDwgSW5qdXJ5LjEuU3RhcnQgfiAnMCcsDQogICAgIWlzLm5hKEluanVyeS4xKSAmIERhdGUgPj0gSW5qdXJ5LjEuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4xIH4gJzEnLA0KICAgICFpcy5uYShJbmp1cnkuMikgJiBEYXRlID49IEluanVyeS4yLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMiB+ICcyJywNCiAgICAhaXMubmEoSW5qdXJ5LjMpICYgRGF0ZSA+PSBJbmp1cnkuMy5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjMgfiAnMycsDQogICAgIWlzLm5hKEluanVyeS40KSAmIERhdGUgPj0gSW5qdXJ5LjQuU3RhcnQgJiBEYXRlIDw9IEluanVyeS40IH4gJzQnLA0KICAgICFpcy5uYShJbmp1cnkuNSkgJiBEYXRlID49IEluanVyeS41LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNSB+ICc1JywNCiAgICAhaXMubmEoSW5qdXJ5LjYpICYgRGF0ZSA+PSBJbmp1cnkuNi5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjYgfiAnNicsDQogICAgIWlzLm5hKEluanVyeS43KSAmIERhdGUgPj0gSW5qdXJ5LjcuU3RhcnQgJiBEYXRlIDw9IEluanVyeS43IH4gJzcnLA0KICAgIFRSVUUgfiAnQWZ0ZXInKSkgJT4lDQogIGZpbHRlcihHcm91cCAhPSAnQWZ0ZXInKQ0KDQojY29uZGVuc2VzIG9ic2VydmF0aW9ucyBiYXNlZCBvbiBncm91cCBhbmQgcGxheWVyIHN1bW1hcml6aW5nIG1lYW5zIG9mIHZhcmlhYmxlcyBvZiBpbnRlcmVzdA0KbWVyZ2VfaGlwX0wgPC0gbWVyZ2VfaGlwX0wgJT4lDQogIG11dGF0ZShJbmp1cnkgPSBjYXNlX3doZW4oDQogICAgR3JvdXAgPT0gMCB+ICdOb25lJywNCiAgICBHcm91cCA9PSAxIH4gSW5qdXJ5LjEuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDIgfiBJbmp1cnkuMi5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gMyB+IEluanVyeS4zLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA0IH4gSW5qdXJ5LjQuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDUgfiBJbmp1cnkuNS5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNiB+IEluanVyeS42LkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA3IH4gSW5qdXJ5LjcuRGlhZ25vc2lzLA0KICAgIFRSVUUgfiAnQWZ0ZXInDQogICksDQogIEFyZWEgPSBjYXNlX3doZW4oDQogICAgR3JvdXAgPT0gMCB+ICdOb25lJywNCiAgICBHcm91cCA9PSAxIH4gSW5qdXJ5LjEuQXJlYSwNCiAgICBHcm91cCA9PSAyIH4gSW5qdXJ5LjIuQXJlYSwNCiAgICBHcm91cCA9PSAzIH4gSW5qdXJ5LjMuQXJlYSwNCiAgICBHcm91cCA9PSA0IH4gSW5qdXJ5LjQuQXJlYSwNCiAgICBHcm91cCA9PSA1IH4gSW5qdXJ5LjUuQXJlYSwNCiAgICBHcm91cCA9PSA2IH4gSW5qdXJ5LjYuQXJlYSwNCiAgICBHcm91cCA9PSA3IH4gSW5qdXJ5LjcuQXJlYSwNCiAgICBUUlVFIH4gJ0FmdGVyJw0KICApKSAlPiUNCiAgbXV0YXRlKFdhcy5Jbmp1cmVkID0gaWZlbHNlKEdyb3VwID09IDEgfCBHcm91cCA9PSAyIHwgR3JvdXAgPT0gMyB8IEdyb3VwID09IDQgfCBHcm91cCA9PSA1IHwgR3JvdXAgPT0gNiB8IEdyb3VwID09IDcsICdZZXMnLCBHcm91cCkpICU+JQ0KICBkcGx5cjo6c2VsZWN0KGFub25faWQsIERhdGUsIEF0aGxldGUuQm9keXdlaWdodC4ua2cuLCBNYXhpbXVtLkZvcmNlLCBBdmVyYWdlLkZvcmNlLCBJbXB1bHNlLCBIaXAuQWJkLkxlZnQuTUVBTiwgSGlwLkFiZC5SaWdodC5NRUFOLCBIaXAuQWJkdWN0aW9uLk1FQU4uSW1iYWxhbmNlLCBIaXAuQWJkLkxlZnQuTUFYLCBIaXAuQWJkLlJpZ2h0Lk1BWCwgSGlwLkFiZHVjdGlvbi5NQVguSW1iYWxhbmNlLCBIaXAuQWRkLkxlZnQuTUVBTiwgSGlwLkFkZC5SaWdodC5NRUFOLCBIaXAuQWRkdWN0aW9uLk1FQU4uSW1iYWxhbmNlLCBIaXAuQWRkLkxlZnQuTUFYLCBIaXAuQWRkLlJpZ2h0Lk1BWCwgSGlwLkFkZHVjdGlvbi5NQVguSW1iYWxhbmNlLCBCaWxhdGVyYWwuSGlwLkFiZHVjdGlvbi5BZGR1Y3Rpb24uUmF0aW8sIFBvc2l0aW9uLCBTcG9ydCwgSW5qdXJ5LCBBcmVhLCBXYXMuSW5qdXJlZCkNCmBgYA0KDQojIyMjIE5vcmRib3JkIERhdGENCg0KKipDTUogRGF0YSoqDQoNCmBgYHtyfQ0KI21lcmdlcyB0aGUgbGFzdF9pbmp1cnlfQiB0byB0aGUgSEpfQiBieSBhbm9uX2lkDQptZXJnZV9jbWpfTCA8LSBtZXJnZShsYXN0X2luanVyeV9MLCBsLCBieSA9IGMoJ2Fub25faWQnKSwgYWxsID0gVFJVRSkNCg0KI2NyZWF0ZXMgYSB2YXJpYWJsZSBjYWxsZWQgR3JvdXAgdGhhdCBncm91cHMgYmFzZWQgb24gZGF0ZSB3aXRoaW4gaW5qdXJ5IGludGVydmFscyBhbmQgb3V0cHV0cyAnQWZ0ZXInIGlmIHRoZSBkYXRlIGlzIGFmdGVyIGFsbCBpbmp1cmllcywgYW5kIHRoZW4gdGhlc2UgYXJlIG9taXR0ZWQNCm1lcmdlX2Ntal9MIDwtIG1lcmdlX2Ntal9MICU+JQ0KICBtdXRhdGUoR3JvdXAgPSBjYXNlX3doZW4oDQogICAgaXMubmEoSW5qdXJ5LjEpIHwgRGF0ZSA8IEluanVyeS4xLlN0YXJ0IH4gJzAnLA0KICAgICFpcy5uYShJbmp1cnkuMSkgJiBEYXRlID49IEluanVyeS4xLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMSB+ICcxJywNCiAgICAhaXMubmEoSW5qdXJ5LjIpICYgRGF0ZSA+PSBJbmp1cnkuMi5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjIgfiAnMicsDQogICAgIWlzLm5hKEluanVyeS4zKSAmIERhdGUgPj0gSW5qdXJ5LjMuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4zIH4gJzMnLA0KICAgICFpcy5uYShJbmp1cnkuNCkgJiBEYXRlID49IEluanVyeS40LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNCB+ICc0JywNCiAgICAhaXMubmEoSW5qdXJ5LjUpICYgRGF0ZSA+PSBJbmp1cnkuNS5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjUgfiAnNScsDQogICAgIWlzLm5hKEluanVyeS42KSAmIERhdGUgPj0gSW5qdXJ5LjYuU3RhcnQgJiBEYXRlIDw9IEluanVyeS42IH4gJzYnLA0KICAgICFpcy5uYShJbmp1cnkuNykgJiBEYXRlID49IEluanVyeS43LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNyB+ICc3JywNCiAgICBUUlVFIH4gJ0FmdGVyJykpICU+JQ0KICBmaWx0ZXIoR3JvdXAgIT0gJ0FmdGVyJykNCg0KI2NvbmRlbnNlcyBvYnNlcnZhdGlvbnMgYmFzZWQgb24gZ3JvdXAgYW5kIHBsYXllciBzdW1tYXJpemluZyBtZWFucyBvZiB2YXJpYWJsZXMgb2YgaW50ZXJlc3QNCm1lcmdlX2Ntal9MIDwtIG1lcmdlX2Ntal9MICU+JQ0KICBtdXRhdGUoSW5qdXJ5ID0gY2FzZV93aGVuKA0KICAgIEdyb3VwID09IDAgfiAnTm9uZScsDQogICAgR3JvdXAgPT0gMSB+IEluanVyeS4xLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSAyIH4gSW5qdXJ5LjIuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDMgfiBJbmp1cnkuMy5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNCB+IEluanVyeS40LkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA1IH4gSW5qdXJ5LjUuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDYgfiBJbmp1cnkuNi5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNyB+IEluanVyeS43LkRpYWdub3NpcywNCiAgICBUUlVFIH4gJ0FmdGVyJw0KICApLA0KICBBcmVhID0gY2FzZV93aGVuKA0KICAgIEdyb3VwID09IDAgfiAnTm9uZScsDQogICAgR3JvdXAgPT0gMSB+IEluanVyeS4xLkFyZWEsDQogICAgR3JvdXAgPT0gMiB+IEluanVyeS4yLkFyZWEsDQogICAgR3JvdXAgPT0gMyB+IEluanVyeS4zLkFyZWEsDQogICAgR3JvdXAgPT0gNCB+IEluanVyeS40LkFyZWEsDQogICAgR3JvdXAgPT0gNSB+IEluanVyeS41LkFyZWEsDQogICAgR3JvdXAgPT0gNiB+IEluanVyeS42LkFyZWEsDQogICAgR3JvdXAgPT0gNyB+IEluanVyeS43LkFyZWEsDQogICAgVFJVRSB+ICdBZnRlcicNCiAgKSkgJT4lDQogIG11dGF0ZShXYXMuSW5qdXJlZCA9IGlmZWxzZShHcm91cCA9PSAxIHwgR3JvdXAgPT0gMiB8IEdyb3VwID09IDMgfCBHcm91cCA9PSA0IHwgR3JvdXAgPT0gNSB8IEdyb3VwID09IDYgfCBHcm91cCA9PSA3LCAnWWVzJywgR3JvdXApKSAlPiUNCiAgZHBseXI6OnNlbGVjdChhbm9uX2lkLCBEYXRlLCBDb3VudGVybW92ZW1lbnQuRGVwdGguLmNtLiwgUGVhay5Qb3dlci4uLkJNLi5XLmtnLiwgTGFuZGluZy5SRkQuLk4ucy4sIEVjY2VudHJpYy5Db25jZW50cmljLk1lYW4uRm9yY2UuUmF0aW8sIFBlYWsuTGFuZGluZy5Gb3JjZS4uQXN5bS4uLk4uLCBQZWFrLlBvd2VyLi5XLiwgQ29uY2VudHJpYy5SRkQuLk4ucy4sIEVjY2VudHJpYy5NZWFuLkJyYWtpbmcuRm9yY2UuLk4uLCBDb25jZW50cmljLlRpbWUudG8uUGVhay5Gb3JjZS4ucy4sIExhbmRpbmcuTmV0LlBlYWsuRm9yY2UuLi5CTS4uTi5rZy4sIFBlYWsuTmV0LlRha2VvZmYuRm9yY2UuLi5CTS4uTi5rZy4sIENvbmNlbnRyaWMuUlBELi4uQk0uLlcucy5rZy4sIEZvcmNlLmF0LlBlYWsuUG93ZXIuLk4uLCBFY2NlbnRyaWMuTWVhbi5EZWNlbGVyYXRpb24uRm9yY2UuLk4uLCBFY2NlbnRyaWMuUGVhay5Gb3JjZS4uTi4sIFJTSS5Nb2RpZmllZC4ubS5zLiwgQ01KLlN0aWZmbmVzcy4uTGVmdC4uLk4ubS4sIENNSi5TdGlmZm5lc3MuLlJpZ2h0Li4uTi5tLiwgRWNjZW50cmljLkFzeW1tZXRyeSwgQ29uY2VudHJpYy5Bc3ltbWV0cnksIFBlYWsuTGFuZGluZy5Bc3ltbWV0cnksIEluanVyeSwgQXJlYSwgV2FzLkluanVyZWQsIFNwb3J0LCBEU0ksIERTSS5CdWNrZXQpDQpgYGANCg0KKipISiBEYXRhKioNCg0KYGBge3J9DQojbWVyZ2VzIHRoZSBsYXN0X2luanVyeV9CIHRvIHRoZSBISl9CIGJ5IGFub25faWQNCm1lcmdlX2hqX0wgPC0gbWVyZ2UobGFzdF9pbmp1cnlfTCwgSEpfTCwgYnkgPSBjKCdhbm9uX2lkJyksIGFsbCA9IFRSVUUpDQoNCiNjcmVhdGVzIGEgdmFyaWFibGUgY2FsbGVkIEdyb3VwIHRoYXQgZ3JvdXBzIGJhc2VkIG9uIGRhdGUgd2l0aGluIGluanVyeSBpbnRlcnZhbHMgYW5kIG91dHB1dHMgJ0FmdGVyJyBpZiB0aGUgZGF0ZSBpcyBhZnRlciBhbGwgaW5qdXJpZXMsIGFuZCB0aGVuIHRoZXNlIGFyZSBvbWl0dGVkDQptZXJnZV9oal9MIDwtIG1lcmdlX2hqX0wgJT4lDQogIG11dGF0ZShHcm91cCA9IGNhc2Vfd2hlbigNCiAgICBpcy5uYShJbmp1cnkuMSkgfCBEYXRlIDwgSW5qdXJ5LjEuU3RhcnQgfiAnMCcsDQogICAgIWlzLm5hKEluanVyeS4xKSAmIERhdGUgPj0gSW5qdXJ5LjEuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4xIH4gJzEnLA0KICAgICFpcy5uYShJbmp1cnkuMikgJiBEYXRlID49IEluanVyeS4yLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMiB+ICcyJywNCiAgICAhaXMubmEoSW5qdXJ5LjMpICYgRGF0ZSA+PSBJbmp1cnkuMy5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjMgfiAnMycsDQogICAgIWlzLm5hKEluanVyeS40KSAmIERhdGUgPj0gSW5qdXJ5LjQuU3RhcnQgJiBEYXRlIDw9IEluanVyeS40IH4gJzQnLA0KICAgICFpcy5uYShJbmp1cnkuNSkgJiBEYXRlID49IEluanVyeS41LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNSB+ICc1JywNCiAgICAhaXMubmEoSW5qdXJ5LjYpICYgRGF0ZSA+PSBJbmp1cnkuNi5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjYgfiAnNicsDQogICAgIWlzLm5hKEluanVyeS43KSAmIERhdGUgPj0gSW5qdXJ5LjcuU3RhcnQgJiBEYXRlIDw9IEluanVyeS43IH4gJzcnLA0KICAgIFRSVUUgfiAnQWZ0ZXInKSkgJT4lDQogIGZpbHRlcihHcm91cCAhPSAnQWZ0ZXInKQ0KDQojY29uZGVuc2VzIG9ic2VydmF0aW9ucyBiYXNlZCBvbiBncm91cCBhbmQgcGxheWVyIHN1bW1hcml6aW5nIG1lYW5zIG9mIHZhcmlhYmxlcyBvZiBpbnRlcmVzdA0KbWVyZ2VfaGpfTCA8LSBtZXJnZV9oal9MICU+JQ0KICBtdXRhdGUoSW5qdXJ5ID0gY2FzZV93aGVuKA0KICAgIEdyb3VwID09IDAgfiAnTm9uZScsDQogICAgR3JvdXAgPT0gMSB+IEluanVyeS4xLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSAyIH4gSW5qdXJ5LjIuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDMgfiBJbmp1cnkuMy5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNCB+IEluanVyeS40LkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA1IH4gSW5qdXJ5LjUuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDYgfiBJbmp1cnkuNi5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNyB+IEluanVyeS43LkRpYWdub3NpcywNCiAgICBUUlVFIH4gJ0FmdGVyJw0KICApLA0KICBBcmVhID0gY2FzZV93aGVuKA0KICAgIEdyb3VwID09IDAgfiAnTm9uZScsDQogICAgR3JvdXAgPT0gMSB+IEluanVyeS4xLkFyZWEsDQogICAgR3JvdXAgPT0gMiB+IEluanVyeS4yLkFyZWEsDQogICAgR3JvdXAgPT0gMyB+IEluanVyeS4zLkFyZWEsDQogICAgR3JvdXAgPT0gNCB+IEluanVyeS40LkFyZWEsDQogICAgR3JvdXAgPT0gNSB+IEluanVyeS41LkFyZWEsDQogICAgR3JvdXAgPT0gNiB+IEluanVyeS42LkFyZWEsDQogICAgR3JvdXAgPT0gNyB+IEluanVyeS43LkFyZWEsDQogICAgVFJVRSB+ICdBZnRlcicNCiAgKSkgJT4lDQogIG11dGF0ZShXYXMuSW5qdXJlZCA9IGlmZWxzZShHcm91cCA9PSAxIHwgR3JvdXAgPT0gMiB8IEdyb3VwID09IDMgfCBHcm91cCA9PSA0IHwgR3JvdXAgPT0gNSB8IEdyb3VwID09IDYgfCBHcm91cCA9PSA3LCAnWWVzJywgR3JvdXApKSAlPiUNCiAgZHBseXI6OnNlbGVjdChhbm9uX2lkLCBEYXRlLCBDb3JyZWN0ZWQuU3RhbmRpbmcuV2VpZ2h0Li5LZy4sIE1lYW4uUlNJLi5GbGlnaHQuQ29udGFjdC5UaW1lLiwgQWN0aXZlLlN0aWZmbmVzcy4uTi5tLiwgQmVzdC5BdmVyYWdlLkZvcmNlLi5OLiwgQmVzdC5BdmVyYWdlLkZvcmNlLi5Bc3ltLi4uTi4sIEJlc3QuVGltZS50by5QZWFrLkZvcmNlLi5tcy4sIEJlc3QuQ29udGFjdC5UaW1lLi5tcy4sIEJlc3QuRmxpZ2h0LlRpbWUuLm1zLiwgQmVzdC5JbXB1bHNlLi5OLnMuLCBCZXN0LlBlYWsuRm9yY2UuLk4uLCBCZXN0LlBlYWsuRm9yY2UuLkFzeW0uLi5OLiwgTWVhbi5BdmVyYWdlLkZvcmNlLi5OLiwgTWVhbi5BdmVyYWdlLkZvcmNlLi5Bc3ltLi4uTi4sIE1lYW4uTGFuZGluZy5SRkQuLk4ucy4sIE1lYW4uTGFuZGluZy5SRkQuLkFzeW0uLi5OLnMuLCBTdGlmZm5lc3MuRmF0aWd1ZS4uLi4sIFN0aWZmbmVzcy5GYXRpZ3VlLi5Bc3ltLi4uLi4sIE1heC5KdW1wLkhlaWdodC4uY20uLCBJbmp1cnksIEFyZWEsIFdhcy5Jbmp1cmVkLCBTcG9ydCwgSEouUlNJLCBNZWFuLkZsaWdodC5UaW1lLi5tcy4sIE1lYW4uQ29udGFjdC5UaW1lLi5tcy4pDQpgYGANCg0KKipJTVRQIERhdGEqKg0KDQpgYGB7cn0NCiNtZXJnZXMgdGhlIGxhc3RfaW5qdXJ5X0IgdG8gdGhlIEhKX0IgYnkgYW5vbl9pZA0KbWVyZ2VfaW10cF9MIDwtIG1lcmdlKGxhc3RfaW5qdXJ5X0wsIElNVFBfTCwgYnkgPSBjKCdhbm9uX2lkJyksIGFsbCA9IFRSVUUpDQoNCiNjcmVhdGVzIGEgdmFyaWFibGUgY2FsbGVkIEdyb3VwIHRoYXQgZ3JvdXBzIGJhc2VkIG9uIGRhdGUgd2l0aGluIGluanVyeSBpbnRlcnZhbHMgYW5kIG91dHB1dHMgJ0FmdGVyJyBpZiB0aGUgZGF0ZSBpcyBhZnRlciBhbGwgaW5qdXJpZXMsIGFuZCB0aGVuIHRoZXNlIGFyZSBvbWl0dGVkDQptZXJnZV9pbXRwX0wgPC0gbWVyZ2VfaW10cF9MICU+JQ0KICBtdXRhdGUoR3JvdXAgPSBjYXNlX3doZW4oDQogICAgaXMubmEoSW5qdXJ5LjEpIHwgRGF0ZSA8IEluanVyeS4xLlN0YXJ0IH4gJzAnLA0KICAgICFpcy5uYShJbmp1cnkuMSkgJiBEYXRlID49IEluanVyeS4xLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMSB+ICcxJywNCiAgICAhaXMubmEoSW5qdXJ5LjIpICYgRGF0ZSA+PSBJbmp1cnkuMi5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjIgfiAnMicsDQogICAgIWlzLm5hKEluanVyeS4zKSAmIERhdGUgPj0gSW5qdXJ5LjMuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4zIH4gJzMnLA0KICAgICFpcy5uYShJbmp1cnkuNCkgJiBEYXRlID49IEluanVyeS40LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNCB+ICc0JywNCiAgICAhaXMubmEoSW5qdXJ5LjUpICYgRGF0ZSA+PSBJbmp1cnkuNS5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjUgfiAnNScsDQogICAgIWlzLm5hKEluanVyeS42KSAmIERhdGUgPj0gSW5qdXJ5LjYuU3RhcnQgJiBEYXRlIDw9IEluanVyeS42IH4gJzYnLA0KICAgICFpcy5uYShJbmp1cnkuNykgJiBEYXRlID49IEluanVyeS43LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNyB+ICc3JywNCiAgICBUUlVFIH4gJ0FmdGVyJykpICU+JQ0KICBmaWx0ZXIoR3JvdXAgIT0gJ0FmdGVyJykNCg0KI2NvbmRlbnNlcyBvYnNlcnZhdGlvbnMgYmFzZWQgb24gZ3JvdXAgYW5kIHBsYXllciBzdW1tYXJpemluZyBtZWFucyBvZiB2YXJpYWJsZXMgb2YgaW50ZXJlc3QNCm1lcmdlX2ltdHBfTCA8LSBtZXJnZV9pbXRwX0wgJT4lDQogIG11dGF0ZShJbmp1cnkgPSBjYXNlX3doZW4oDQogICAgR3JvdXAgPT0gMCB+ICdOb25lJywNCiAgICBHcm91cCA9PSAxIH4gSW5qdXJ5LjEuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDIgfiBJbmp1cnkuMi5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gMyB+IEluanVyeS4zLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA0IH4gSW5qdXJ5LjQuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDUgfiBJbmp1cnkuNS5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNiB+IEluanVyeS42LkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA3IH4gSW5qdXJ5LjcuRGlhZ25vc2lzLA0KICAgIFRSVUUgfiAnQWZ0ZXInDQogICksDQogIEFyZWEgPSBjYXNlX3doZW4oDQogICAgR3JvdXAgPT0gMCB+ICdOb25lJywNCiAgICBHcm91cCA9PSAxIH4gSW5qdXJ5LjEuQXJlYSwNCiAgICBHcm91cCA9PSAyIH4gSW5qdXJ5LjIuQXJlYSwNCiAgICBHcm91cCA9PSAzIH4gSW5qdXJ5LjMuQXJlYSwNCiAgICBHcm91cCA9PSA0IH4gSW5qdXJ5LjQuQXJlYSwNCiAgICBHcm91cCA9PSA1IH4gSW5qdXJ5LjUuQXJlYSwNCiAgICBHcm91cCA9PSA2IH4gSW5qdXJ5LjYuQXJlYSwNCiAgICBHcm91cCA9PSA3IH4gSW5qdXJ5LjcuQXJlYSwNCiAgICBUUlVFIH4gJ0FmdGVyJw0KICApKSAlPiUNCiAgbXV0YXRlKFdhcy5Jbmp1cmVkID0gaWZlbHNlKEdyb3VwID09IDEgfCBHcm91cCA9PSAyIHwgR3JvdXAgPT0gMyB8IEdyb3VwID09IDQgfCBHcm91cCA9PSA1IHwgR3JvdXAgPT0gNiB8IEdyb3VwID09IDcsICdZZXMnLCBHcm91cCkpICU+JQ0KICBkcGx5cjo6c2VsZWN0KGFub25faWQsIERhdGUsIEJhc2VsaW5lLkZvcmNlLi5OLiwgQmFzZWxpbmUuRm9yY2UuLkFzeW0uLi5OLiwgUGVhay5WZXJ0aWNhbC5Gb3JjZS4uTi4sIFBlYWsuVmVydGljYWwuRm9yY2UuLi5CTS4uTi5rZy4sIFBlYWsuVmVydGljYWwuRm9yY2UuLkFzeW0uLi5OLiwgUkZELi4uNTBtcy4uTi5zLiwgUkZELi4uNTBtcy4uQXN5bS4uLk4ucy4sIFJGRC4uLjEwMG1zLi5OLnMuLCBSRkQuLi4xMDBtcy4uQXN5bS4uLk4ucy4sIFJGRC4uLjE1MG1zLi5OLnMuLCBSRkQuLi4xNTBtcy4uQXN5bS4uLk4ucy4sIFJGRC4uLjIwMG1zLi5OLnMuLCBSRkQuLi4yMDBtcy4uQXN5bS4uLk4ucy4sIE5ldC5QZWFrLlZlcnRpY2FsLkZvcmNlLi5OLnMuLCBOZXQuUGVhay5WZXJ0aWNhbC5Gb3JjZS4uQXN5bS4uLk4ucy4sIEZvcmNlLmF0LjIwMG1zLi4uQk0uLk4ua2cuLCBJbmp1cnksIEFyZWEsIFdhcy5Jbmp1cmVkLCBTcG9ydCkNCmBgYA0KDQojIyMgNC4gVm9sbGV5YmFsbA0KDQpgYGB7cn0NCiNzZWxlY3RzIHZhcmlhYmxlcyBvZiBpbnRlcmVzdCwgZmlsdGVycyBmb3IgbG93ZXIgYm9keSBpbmp1cmllcywgYW5kIGdldHMgcmlkIG9mIGR1cGxpY2F0ZSBvYnNlcnZhdGlvbnMNCmluY2lkX3YgPC0gSW5jaWRlbnRfViAlPiUNCiAgZmlsdGVyKEJvZHkuUGFydCAlaW4lIGxvd2VyX2JvZHkpICU+JQ0KICBkcGx5cjo6c2VsZWN0KCJhbm9uX2lkIiwgIlBvc2l0aW9uIiwgIkRhdGUub2YuSW5qdXJ5Li4uT25zZXQub2Yuc3ltcHRvbXMiLCAiU2lkZSIsICJCb2R5LlBhcnQiLCAiVGlzc3VlLlR5cGUiLCAiUGF0aG9sb2d5LlR5cGUiLCAiT1NJQ1MxNC5Db2RlIiwgIk9TSUNTMTAuQ29kZSIsICJPU0lDUzEwLkRpYWdub3NpcyIsICJGaW5hbC5EaWFnbm9zaXMiLCAiUmVjdXJyZW5jZS5vZi5Jbmp1cnkiLCAiSW5qdXJ5LlByb2dub3NpcyIsICJHZW5lcmFsLk1lY2hhbmlzbSIsICJTcGVjaWZpYy5NZWNoYW5pc20iLCAiRmluYWxEaWFnbm9zaXNJbmNpZGVudERhdGUiLCAiVG90YWwuVGltZS5Jbmp1cmVkIiwgIlNlYXNvbi4iKSAlPiUNCiAgZ3JvdXBfYnkoYW5vbl9pZCwgRGF0ZS5vZi5Jbmp1cnkuLi5PbnNldC5vZi5zeW1wdG9tcykgJT4lDQogIG11dGF0ZShUb3RhbC5UaW1lLkluanVyZWQgPSBzdW0oVG90YWwuVGltZS5Jbmp1cmVkLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgRGF0ZSA9IGFzLkRhdGUoRGF0ZS5vZi5Jbmp1cnkuLi5PbnNldC5vZi5zeW1wdG9tcywgZm9ybWF0ID0gJyVtLyVkLyVZJyksDQogICAgICAgICBTZWFzb24uID0gaWZlbHNlKFNlYXNvbi4gPT0gJ1ByZS1TZWFzb24nIHwgU2Vhc29uLiA9PSAnU3VtbWVyIFdvcmtvdXRzJyB8IFNlYXNvbi4gPT0gJ1Bvc3QtU2Vhc29uJywgJ09mZi1TZWFzb24nLCBTZWFzb24uKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgZ3JvdXBfYnkoYWNyb3NzKGV2ZXJ5dGhpbmcoKSkpICU+JQ0KICBzdW1tYXJpc2UoLmdyb3VwcyA9ICdkcm9wJykNCmBgYA0KDQpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQ0KI2NyZWF0ZXMgYSBkYXRhc2V0IGZyb20gdGhlIGluY2lkZW50IHJlcG9ydCB0aGF0IHNlcGFyYXRlcyBvdXQgYWxsIHRoZSBkYXRlcyBmb3IgbG93ZXIgYm9keSBpbmp1cmllcyB0byBjbGFzc2lmeSBvYnNlcnZhdGlvbnMgYmFzZWQgb24gdGhlaXIgcmVsYXRpb24gdG8gbG93ZXIgYm9keSBpbmp1cmllczogd2l0aGluIDMgbW9udGhzIHByaW9yIHRvIGZpcnN0IGluanVyeSwgYmV0d2VlbiBmaXJzdCBhbmQgc2Vjb25kIGluanVyeSwgZWN0Lg0KbGFzdF9pbmp1cnlfViA8LSBpbmNpZF92ICU+JQ0KICBhcnJhbmdlKERhdGUpICU+JQ0KICBncm91cF9ieShhbm9uX2lkKSAlPiUNCiAgc3VtbWFyaXplKERhdGVzLkZpbmFsID0gcGFzdGUwKERhdGUsIGNvbGxhcHNlID0gIiBhbmQgIiksDQogICAgICAgICAgICBNZWNoYW5pc20gPSBwYXN0ZTAoR2VuZXJhbC5NZWNoYW5pc20sIGNvbGxhcHNlID0gIiBhbmQgIiksDQogICAgICAgICAgICBJbmp1cnkgPSBwYXN0ZTAoRmluYWwuRGlhZ25vc2lzLCBjb2xsYXBzZSA9ICIgYW5kICIpLA0KICAgICAgICAgICAgQXJlYSA9IHBhc3RlMChCb2R5LlBhcnQsIGNvbGxhcHNlID0gIiBhbmQgIiksDQogICAgICAgICAgICBUaW1lLkluanVyZWQgPSBwYXN0ZTAoVG90YWwuVGltZS5Jbmp1cmVkLCBjb2xsYXBzZSA9ICIgYW5kICIpKSAlPiUNCiAgc2VwYXJhdGUoRGF0ZXMuRmluYWwsIGMoJ0luanVyeS4xJywgJ0luanVyeS4yJywgJ0luanVyeS4zJywgJ0luanVyeS40JywgJ0luanVyeS41JywgJ0luanVyeS42JywgJ0luanVyeS43JyksIHNlcCA9ICcgYW5kICcpICU+JQ0KICBtdXRhdGUoSW5qdXJ5LjEuU3RhcnQgPSBhcy5EYXRlKEluanVyeS4xKSAtIG1vbnRocygzKSwNCiAgICAgICAgIEluanVyeS4yLlN0YXJ0ID0gaWZlbHNlKGlzLm5hKEluanVyeS4yKSwgTkEsIEluanVyeS4xKSwNCiAgICAgICAgIEluanVyeS4zLlN0YXJ0ID0gaWZlbHNlKGlzLm5hKEluanVyeS4zKSwgTkEsIEluanVyeS4yKSwNCiAgICAgICAgIEluanVyeS40LlN0YXJ0ID0gaWZlbHNlKGlzLm5hKEluanVyeS40KSwgTkEsIEluanVyeS4zKSwNCiAgICAgICAgIEluanVyeS41LlN0YXJ0ID0gaWZlbHNlKGlzLm5hKEluanVyeS40KSwgTkEsIEluanVyeS40KSwNCiAgICAgICAgIEluanVyeS42LlN0YXJ0ID0gaWZlbHNlKGlzLm5hKEluanVyeS40KSwgTkEsIEluanVyeS41KSwNCiAgICAgICAgIEluanVyeS43LlN0YXJ0ID0gaWZlbHNlKGlzLm5hKEluanVyeS40KSwgTkEsIEluanVyeS42KSkgJT4lDQogIHNlcGFyYXRlKE1lY2hhbmlzbSwgYygnSW5qdXJ5LjEuTWVjaCcsICdJbmp1cnkuMi5NZWNoJywgJ0luanVyeS4zLk1lY2gnLCAnSW5qdXJ5LjQuTWVjaCcsICdJbmp1cnkuNS5NZWNoJywgJ0luanVyeS42Lk1lY2gnLCAnSW5qdXJ5LjcuTWVjaCcpLCBzZXAgPSAnIGFuZCAnKSAlPiUNCiAgc2VwYXJhdGUoSW5qdXJ5LCBjKCdJbmp1cnkuMS5EaWFnbm9zaXMnLCAnSW5qdXJ5LjIuRGlhZ25vc2lzJywgJ0luanVyeS4zLkRpYWdub3NpcycsICdJbmp1cnkuNC5EaWFnbm9zaXMnLCAnSW5qdXJ5LjUuRGlhZ25vc2lzJywgJ0luanVyeS42LkRpYWdub3NpcycsICdJbmp1cnkuNy5EaWFnbm9zaXMnKSwgc2VwID0gJyBhbmQgJykgJT4lDQogIHNlcGFyYXRlKFRpbWUuSW5qdXJlZCwgYygnSW5qdXJ5LjEuVGltZScsICdJbmp1cnkuMi5UaW1lJywgJ0luanVyeS4zLlRpbWUnLCAnSW5qdXJ5LjQuVGltZScsICdJbmp1cnkuNS5UaW1lJywgJ0luanVyeS42LlRpbWUnLCAnSW5qdXJ5LjcuVGltZScpLCBzZXAgPSAnIGFuZCAnKSAlPiUNCiAgc2VwYXJhdGUoQXJlYSwgYygnSW5qdXJ5LjEuQXJlYScsICdJbmp1cnkuMi5BcmVhJywgJ0luanVyeS4zLkFyZWEnLCAnSW5qdXJ5LjQuQXJlYScsICdJbmp1cnkuNS5BcmVhJywgJ0luanVyeS42LkFyZWEnLCAnSW5qdXJ5LjcuQXJlYScpLCBzZXAgPSAnIGFuZCAnKQ0KYGBgDQoNCiMjIyMgUGVyZm9ybWFuY2UgRGF0YQ0KDQoqKk5vcmRpYyBEYXRhKioNCg0KYGBge3J9DQojbWVyZ2VzIHRoZSBsYXN0X2luanVyeV9TIHRvIHRoZSBwZXJmb3JtYW5jZV9TX25vcmRpYyBieSBhbm9uX2lkDQptZXJnZV9wZXJmb3JtYW5jZV9WIDwtIG1lcmdlKGxhc3RfaW5qdXJ5X1YsIHBlcmZvcm1hbmNlX1Zfbm9yZGljLCBieSA9IGMoJ2Fub25faWQnKSwgYWxsID0gVFJVRSkNCg0KI2NyZWF0ZXMgYSB2YXJpYWJsZSBjYWxsZWQgR3JvdXAgdGhhdCBncm91cHMgYmFzZWQgb24gZGF0ZSB3aXRoaW4gaW5qdXJ5IGludGVydmFscyBhbmQgb3V0cHV0cyAnQWZ0ZXInIGlmIHRoZSBkYXRlIGlzIGFmdGVyIGFsbCBpbmp1cmllcywgYW5kIHRoZW4gdGhlc2UgYXJlIG9taXR0ZWQNCm1lcmdlX3BlcmZvcm1hbmNlX1YgPC0gbWVyZ2VfcGVyZm9ybWFuY2VfViAlPiUNCiAgbXV0YXRlKFRyZW5kID0gaWZlbHNlKFRyZW5kID09ICdOZXV0cmFsJywgMCwgaWZlbHNlKFRyZW5kID09ICdVcCcsIDEsIC0xKSksDQogICAgICAgICBHcm91cCA9IGNhc2Vfd2hlbigNCiAgICBpcy5uYShJbmp1cnkuMSkgfCBEYXRlIDwgSW5qdXJ5LjEuU3RhcnQgfiAnMCcsDQogICAgIWlzLm5hKEluanVyeS4xKSAmIERhdGUgPj0gSW5qdXJ5LjEuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4xIH4gJzEnLA0KICAgICFpcy5uYShJbmp1cnkuMikgJiBEYXRlID49IEluanVyeS4yLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMiB+ICcyJywNCiAgICAhaXMubmEoSW5qdXJ5LjMpICYgRGF0ZSA+PSBJbmp1cnkuMy5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjMgfiAnMycsDQogICAgIWlzLm5hKEluanVyeS40KSAmIERhdGUgPj0gSW5qdXJ5LjQuU3RhcnQgJiBEYXRlIDw9IEluanVyeS40IH4gJzQnLA0KICAgICFpcy5uYShJbmp1cnkuNSkgJiBEYXRlID49IEluanVyeS41LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNSB+ICc1JywNCiAgICAhaXMubmEoSW5qdXJ5LjYpICYgRGF0ZSA+PSBJbmp1cnkuNi5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjYgfiAnNicsDQogICAgIWlzLm5hKEluanVyeS43KSAmIERhdGUgPj0gSW5qdXJ5LjcuU3RhcnQgJiBEYXRlIDw9IEluanVyeS43IH4gJzcnLA0KICAgIFRSVUUgfiAnQWZ0ZXInKSkgJT4lDQogIGZpbHRlcihHcm91cCAhPSAnQWZ0ZXInKQ0KDQojY29uZGVuc2VzIG9ic2VydmF0aW9ucyBiYXNlZCBvbiBncm91cCBhbmQgcGxheWVyIHN1bW1hcml6aW5nIG1lYW5zIG9mIHZhcmlhYmxlcyBvZiBpbnRlcmVzdA0KbWVyZ2VfcGVyZm9ybWFuY2VfViA8LSBtZXJnZV9wZXJmb3JtYW5jZV9WICU+JQ0KICBtdXRhdGUoSW5qdXJ5ID0gY2FzZV93aGVuKA0KICAgIEdyb3VwID09IDAgfiAnTm9uZScsDQogICAgR3JvdXAgPT0gMSB+IEluanVyeS4xLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSAyIH4gSW5qdXJ5LjIuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDMgfiBJbmp1cnkuMy5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNCB+IEluanVyeS40LkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA1IH4gSW5qdXJ5LjUuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDYgfiBJbmp1cnkuNi5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNyB+IEluanVyeS43LkRpYWdub3NpcywNCiAgICBUUlVFIH4gJ0FmdGVyJw0KICApLA0KICBBcmVhID0gY2FzZV93aGVuKA0KICAgIEdyb3VwID09IDAgfiAnTm9uZScsDQogICAgR3JvdXAgPT0gMSB+IEluanVyeS4xLkFyZWEsDQogICAgR3JvdXAgPT0gMiB+IEluanVyeS4yLkFyZWEsDQogICAgR3JvdXAgPT0gMyB+IEluanVyeS4zLkFyZWEsDQogICAgR3JvdXAgPT0gNCB+IEluanVyeS40LkFyZWEsDQogICAgR3JvdXAgPT0gNSB+IEluanVyeS41LkFyZWEsDQogICAgR3JvdXAgPT0gNiB+IEluanVyeS42LkFyZWEsDQogICAgR3JvdXAgPT0gNyB+IEluanVyeS43LkFyZWEsDQogICAgVFJVRSB+ICdBZnRlcicNCiAgKSkgJT4lDQogIG11dGF0ZShXYXMuSW5qdXJlZCA9IGlmZWxzZShHcm91cCA9PSAxIHwgR3JvdXAgPT0gMiB8IEdyb3VwID09IDMgfCBHcm91cCA9PSA0IHwgR3JvdXAgPT0gNSB8IEdyb3VwID09IDYgfCBHcm91cCA9PSA3LCAnWWVzJywgR3JvdXApKSAlPiUNCiAgZHBseXI6OnNlbGVjdChhbm9uX2lkLCBEYXRlLCBBdGhsZXRlLkJvZHl3ZWlnaHQuLmtnLiwgTWF4aW11bS5Gb3JjZSwgQXZlcmFnZS5Gb3JjZSwgSW1wdWxzZSwgTm9yZGljLkxlZnQuTUVBTiwgTm9yZGljLlJpZ2h0Lk1FQU4sIE5vcmRpYy5NRUFOLkltYmFsYW5jZSwgTm9yZGljLkxlZnQuTUFYLCBOb3JkaWMuUmlnaHQuTUFYLCBOb3JkaWMuTUFYLkltYmFsYW5jZSwgVHJlbmQsIE5vcmRpYy4uLkRpZmZlcmVuY2UuZnJvbS5GaXJzdC5UZXN0LCBNYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbiwgUmVsYXRpdmUuTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4sIFBvc2l0aW9uLCBTcG9ydCwgSW5qdXJ5LCBBcmVhLCBXYXMuSW5qdXJlZCwgRm9yY2UuRGlmZi5Ob3JtLCBJbWJhbGFuY2UuRGlmZi5Ob3JtKQ0KYGBgDQoNCioqSGlwIERhdGEqKg0KDQpgYGB7cn0NCiNtZXJnZXMgdGhlIGxhc3RfaW5qdXJ5X1YgdG8gdGhlIHBlcmZvcm1hbmNlX1Zfbm9yZGljIGJ5IGFub25faWQNCm1lcmdlX2hpcF9WIDwtIG1lcmdlKGxhc3RfaW5qdXJ5X1YsIHBlcmZvcm1hbmNlX1ZfaGlwLCBieSA9IGMoJ2Fub25faWQnKSwgYWxsID0gVFJVRSkNCg0KI2NyZWF0ZXMgYSB2YXJpYWJsZSBjYWxsZWQgR3JvdXAgdGhhdCBncm91cHMgYmFzZWQgb24gZGF0ZSB3aXRoaW4gaW5qdXJ5IGludGVydmFscyBhbmQgb3V0cHV0cyAnQWZ0ZXInIGlmIHRoZSBkYXRlIGlzIGFmdGVyIGFsbCBpbmp1cmllcywgYW5kIHRoZW4gdGhlc2UgYXJlIG9taXR0ZWQNCm1lcmdlX2hpcF9WIDwtIG1lcmdlX2hpcF9WICU+JQ0KICBtdXRhdGUoR3JvdXAgPSBjYXNlX3doZW4oDQogICAgaXMubmEoSW5qdXJ5LjEpIHwgRGF0ZSA8IEluanVyeS4xLlN0YXJ0IH4gJzAnLA0KICAgICFpcy5uYShJbmp1cnkuMSkgJiBEYXRlID49IEluanVyeS4xLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMSB+ICcxJywNCiAgICAhaXMubmEoSW5qdXJ5LjIpICYgRGF0ZSA+PSBJbmp1cnkuMi5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjIgfiAnMicsDQogICAgIWlzLm5hKEluanVyeS4zKSAmIERhdGUgPj0gSW5qdXJ5LjMuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4zIH4gJzMnLA0KICAgICFpcy5uYShJbmp1cnkuNCkgJiBEYXRlID49IEluanVyeS40LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNCB+ICc0JywNCiAgICAhaXMubmEoSW5qdXJ5LjUpICYgRGF0ZSA+PSBJbmp1cnkuNS5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjUgfiAnNScsDQogICAgIWlzLm5hKEluanVyeS42KSAmIERhdGUgPj0gSW5qdXJ5LjYuU3RhcnQgJiBEYXRlIDw9IEluanVyeS42IH4gJzYnLA0KICAgICFpcy5uYShJbmp1cnkuNykgJiBEYXRlID49IEluanVyeS43LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNyB+ICc3JywNCiAgICBUUlVFIH4gJ0FmdGVyJykpICU+JQ0KICBmaWx0ZXIoR3JvdXAgIT0gJ0FmdGVyJykNCg0KI2NvbmRlbnNlcyBvYnNlcnZhdGlvbnMgYmFzZWQgb24gZ3JvdXAgYW5kIHBsYXllciBzdW1tYXJpemluZyBtZWFucyBvZiB2YXJpYWJsZXMgb2YgaW50ZXJlc3QNCm1lcmdlX2hpcF9WIDwtIG1lcmdlX2hpcF9WICU+JQ0KICBtdXRhdGUoSW5qdXJ5ID0gY2FzZV93aGVuKA0KICAgIEdyb3VwID09IDAgfiAnTm9uZScsDQogICAgR3JvdXAgPT0gMSB+IEluanVyeS4xLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSAyIH4gSW5qdXJ5LjIuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDMgfiBJbmp1cnkuMy5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNCB+IEluanVyeS40LkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA1IH4gSW5qdXJ5LjUuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDYgfiBJbmp1cnkuNi5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNyB+IEluanVyeS43LkRpYWdub3NpcywNCiAgICBUUlVFIH4gJ0FmdGVyJw0KICApLA0KICBBcmVhID0gY2FzZV93aGVuKA0KICAgIEdyb3VwID09IDAgfiAnTm9uZScsDQogICAgR3JvdXAgPT0gMSB+IEluanVyeS4xLkFyZWEsDQogICAgR3JvdXAgPT0gMiB+IEluanVyeS4yLkFyZWEsDQogICAgR3JvdXAgPT0gMyB+IEluanVyeS4zLkFyZWEsDQogICAgR3JvdXAgPT0gNCB+IEluanVyeS40LkFyZWEsDQogICAgR3JvdXAgPT0gNSB+IEluanVyeS41LkFyZWEsDQogICAgR3JvdXAgPT0gNiB+IEluanVyeS42LkFyZWEsDQogICAgR3JvdXAgPT0gNyB+IEluanVyeS43LkFyZWEsDQogICAgVFJVRSB+ICdBZnRlcicNCiAgKSkgJT4lDQogIG11dGF0ZShXYXMuSW5qdXJlZCA9IGlmZWxzZShHcm91cCA9PSAxIHwgR3JvdXAgPT0gMiB8IEdyb3VwID09IDMgfCBHcm91cCA9PSA0IHwgR3JvdXAgPT0gNSB8IEdyb3VwID09IDYgfCBHcm91cCA9PSA3LCAnWWVzJywgR3JvdXApKSAlPiUNCiAgZHBseXI6OnNlbGVjdChhbm9uX2lkLCBEYXRlLCBBdGhsZXRlLkJvZHl3ZWlnaHQuLmtnLiwgTWF4aW11bS5Gb3JjZSwgQXZlcmFnZS5Gb3JjZSwgSW1wdWxzZSwgSGlwLkFiZC5MZWZ0Lk1FQU4sIEhpcC5BYmQuUmlnaHQuTUVBTiwgSGlwLkFiZHVjdGlvbi5NRUFOLkltYmFsYW5jZSwgSGlwLkFiZC5MZWZ0Lk1BWCwgSGlwLkFiZC5SaWdodC5NQVgsIEhpcC5BYmR1Y3Rpb24uTUFYLkltYmFsYW5jZSwgSGlwLkFkZC5MZWZ0Lk1FQU4sIEhpcC5BZGQuUmlnaHQuTUVBTiwgSGlwLkFkZHVjdGlvbi5NRUFOLkltYmFsYW5jZSwgSGlwLkFkZC5MZWZ0Lk1BWCwgSGlwLkFkZC5SaWdodC5NQVgsIEhpcC5BZGR1Y3Rpb24uTUFYLkltYmFsYW5jZSwgQmlsYXRlcmFsLkhpcC5BYmR1Y3Rpb24uQWRkdWN0aW9uLlJhdGlvLCBQb3NpdGlvbiwgU3BvcnQsIEluanVyeSwgQXJlYSwgV2FzLkluanVyZWQpDQpgYGANCg0KIyMjIyBOb3JkYm9yZCBEYXRhDQoNCioqQ01KIERhdGEqKg0KDQpgYGB7cn0NCiNtZXJnZXMgdGhlIGxhc3RfaW5qdXJ5X0IgdG8gdGhlIEhKX0IgYnkgYW5vbl9pZA0KbWVyZ2VfY21qX1YgPC0gbWVyZ2UobGFzdF9pbmp1cnlfViwgdiwgYnkgPSBjKCdhbm9uX2lkJyksIGFsbCA9IFRSVUUpDQoNCiNjcmVhdGVzIGEgdmFyaWFibGUgY2FsbGVkIEdyb3VwIHRoYXQgZ3JvdXBzIGJhc2VkIG9uIGRhdGUgd2l0aGluIGluanVyeSBpbnRlcnZhbHMgYW5kIG91dHB1dHMgJ0FmdGVyJyBpZiB0aGUgZGF0ZSBpcyBhZnRlciBhbGwgaW5qdXJpZXMsIGFuZCB0aGVuIHRoZXNlIGFyZSBvbWl0dGVkDQptZXJnZV9jbWpfViA8LSBtZXJnZV9jbWpfViAlPiUNCiAgbXV0YXRlKEdyb3VwID0gY2FzZV93aGVuKA0KICAgIGlzLm5hKEluanVyeS4xKSB8IERhdGUgPCBJbmp1cnkuMS5TdGFydCB+ICcwJywNCiAgICAhaXMubmEoSW5qdXJ5LjEpICYgRGF0ZSA+PSBJbmp1cnkuMS5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjEgfiAnMScsDQogICAgIWlzLm5hKEluanVyeS4yKSAmIERhdGUgPj0gSW5qdXJ5LjIuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4yIH4gJzInLA0KICAgICFpcy5uYShJbmp1cnkuMykgJiBEYXRlID49IEluanVyeS4zLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMyB+ICczJywNCiAgICAhaXMubmEoSW5qdXJ5LjQpICYgRGF0ZSA+PSBJbmp1cnkuNC5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjQgfiAnNCcsDQogICAgIWlzLm5hKEluanVyeS41KSAmIERhdGUgPj0gSW5qdXJ5LjUuU3RhcnQgJiBEYXRlIDw9IEluanVyeS41IH4gJzUnLA0KICAgICFpcy5uYShJbmp1cnkuNikgJiBEYXRlID49IEluanVyeS42LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNiB+ICc2JywNCiAgICAhaXMubmEoSW5qdXJ5LjcpICYgRGF0ZSA+PSBJbmp1cnkuNy5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjcgfiAnNycsDQogICAgVFJVRSB+ICdBZnRlcicpKSAlPiUNCiAgZmlsdGVyKEdyb3VwICE9ICdBZnRlcicpDQoNCiNjb25kZW5zZXMgb2JzZXJ2YXRpb25zIGJhc2VkIG9uIGdyb3VwIGFuZCBwbGF5ZXIgc3VtbWFyaXppbmcgbWVhbnMgb2YgdmFyaWFibGVzIG9mIGludGVyZXN0DQptZXJnZV9jbWpfViA8LSBtZXJnZV9jbWpfViAlPiUNCiAgbXV0YXRlKEluanVyeSA9IGNhc2Vfd2hlbigNCiAgICBHcm91cCA9PSAwIH4gJ05vbmUnLA0KICAgIEdyb3VwID09IDEgfiBJbmp1cnkuMS5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gMiB+IEluanVyeS4yLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSAzIH4gSW5qdXJ5LjMuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDQgfiBJbmp1cnkuNC5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNSB+IEluanVyeS41LkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA2IH4gSW5qdXJ5LjYuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDcgfiBJbmp1cnkuNy5EaWFnbm9zaXMsDQogICAgVFJVRSB+ICdBZnRlcicNCiAgKSwNCiAgQXJlYSA9IGNhc2Vfd2hlbigNCiAgICBHcm91cCA9PSAwIH4gJ05vbmUnLA0KICAgIEdyb3VwID09IDEgfiBJbmp1cnkuMS5BcmVhLA0KICAgIEdyb3VwID09IDIgfiBJbmp1cnkuMi5BcmVhLA0KICAgIEdyb3VwID09IDMgfiBJbmp1cnkuMy5BcmVhLA0KICAgIEdyb3VwID09IDQgfiBJbmp1cnkuNC5BcmVhLA0KICAgIEdyb3VwID09IDUgfiBJbmp1cnkuNS5BcmVhLA0KICAgIEdyb3VwID09IDYgfiBJbmp1cnkuNi5BcmVhLA0KICAgIEdyb3VwID09IDcgfiBJbmp1cnkuNy5BcmVhLA0KICAgIFRSVUUgfiAnQWZ0ZXInDQogICkpICU+JQ0KICBtdXRhdGUoV2FzLkluanVyZWQgPSBpZmVsc2UoR3JvdXAgPT0gMSB8IEdyb3VwID09IDIgfCBHcm91cCA9PSAzIHwgR3JvdXAgPT0gNCB8IEdyb3VwID09IDUgfCBHcm91cCA9PSA2IHwgR3JvdXAgPT0gNywgJ1llcycsIEdyb3VwKSkgJT4lDQogIGRwbHlyOjpzZWxlY3QoYW5vbl9pZCwgRGF0ZSwgQ291bnRlcm1vdmVtZW50LkRlcHRoLi5jbS4sIFBlYWsuUG93ZXIuLi5CTS4uVy5rZy4sIExhbmRpbmcuUkZELi5OLnMuLCBFY2NlbnRyaWMuQ29uY2VudHJpYy5NZWFuLkZvcmNlLlJhdGlvLCBQZWFrLkxhbmRpbmcuRm9yY2UuLkFzeW0uLi5OLiwgUGVhay5Qb3dlci4uVy4sIENvbmNlbnRyaWMuUkZELi5OLnMuLCBFY2NlbnRyaWMuTWVhbi5CcmFraW5nLkZvcmNlLi5OLiwgQ29uY2VudHJpYy5UaW1lLnRvLlBlYWsuRm9yY2UuLnMuLCBMYW5kaW5nLk5ldC5QZWFrLkZvcmNlLi4uQk0uLk4ua2cuLCBQZWFrLk5ldC5UYWtlb2ZmLkZvcmNlLi4uQk0uLk4ua2cuLCBDb25jZW50cmljLlJQRC4uLkJNLi5XLnMua2cuLCBGb3JjZS5hdC5QZWFrLlBvd2VyLi5OLiwgRWNjZW50cmljLk1lYW4uRGVjZWxlcmF0aW9uLkZvcmNlLi5OLiwgRWNjZW50cmljLlBlYWsuRm9yY2UuLk4uLCBSU0kuTW9kaWZpZWQuLm0ucy4sIENNSi5TdGlmZm5lc3MuLkxlZnQuLi5OLm0uLCBDTUouU3RpZmZuZXNzLi5SaWdodC4uLk4ubS4sIEVjY2VudHJpYy5Bc3ltbWV0cnksIENvbmNlbnRyaWMuQXN5bW1ldHJ5LCBQZWFrLkxhbmRpbmcuQXN5bW1ldHJ5LCBJbmp1cnksIEFyZWEsIFdhcy5Jbmp1cmVkLCBTcG9ydCwgRFNJLCBEU0kuQnVja2V0KQ0KYGBgDQoNCioqSEogRGF0YSoqDQoNCmBgYHtyfQ0KI21lcmdlcyB0aGUgbGFzdF9pbmp1cnlfQiB0byB0aGUgSEpfQiBieSBhbm9uX2lkDQptZXJnZV9oal9WIDwtIG1lcmdlKGxhc3RfaW5qdXJ5X1YsIEhKX1YsIGJ5ID0gYygnYW5vbl9pZCcpLCBhbGwgPSBUUlVFKQ0KDQojY3JlYXRlcyBhIHZhcmlhYmxlIGNhbGxlZCBHcm91cCB0aGF0IGdyb3VwcyBiYXNlZCBvbiBkYXRlIHdpdGhpbiBpbmp1cnkgaW50ZXJ2YWxzIGFuZCBvdXRwdXRzICdBZnRlcicgaWYgdGhlIGRhdGUgaXMgYWZ0ZXIgYWxsIGluanVyaWVzLCBhbmQgdGhlbiB0aGVzZSBhcmUgb21pdHRlZA0KbWVyZ2VfaGpfViA8LSBtZXJnZV9oal9WICU+JQ0KICBtdXRhdGUoR3JvdXAgPSBjYXNlX3doZW4oDQogICAgaXMubmEoSW5qdXJ5LjEpIHwgRGF0ZSA8IEluanVyeS4xLlN0YXJ0IH4gJzAnLA0KICAgICFpcy5uYShJbmp1cnkuMSkgJiBEYXRlID49IEluanVyeS4xLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMSB+ICcxJywNCiAgICAhaXMubmEoSW5qdXJ5LjIpICYgRGF0ZSA+PSBJbmp1cnkuMi5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjIgfiAnMicsDQogICAgIWlzLm5hKEluanVyeS4zKSAmIERhdGUgPj0gSW5qdXJ5LjMuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4zIH4gJzMnLA0KICAgICFpcy5uYShJbmp1cnkuNCkgJiBEYXRlID49IEluanVyeS40LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNCB+ICc0JywNCiAgICAhaXMubmEoSW5qdXJ5LjUpICYgRGF0ZSA+PSBJbmp1cnkuNS5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjUgfiAnNScsDQogICAgIWlzLm5hKEluanVyeS42KSAmIERhdGUgPj0gSW5qdXJ5LjYuU3RhcnQgJiBEYXRlIDw9IEluanVyeS42IH4gJzYnLA0KICAgICFpcy5uYShJbmp1cnkuNykgJiBEYXRlID49IEluanVyeS43LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNyB+ICc3JywNCiAgICBUUlVFIH4gJ0FmdGVyJykpICU+JQ0KICBmaWx0ZXIoR3JvdXAgIT0gJ0FmdGVyJykNCg0KI2NvbmRlbnNlcyBvYnNlcnZhdGlvbnMgYmFzZWQgb24gZ3JvdXAgYW5kIHBsYXllciBzdW1tYXJpemluZyBtZWFucyBvZiB2YXJpYWJsZXMgb2YgaW50ZXJlc3QNCm1lcmdlX2hqX1YgPC0gbWVyZ2VfaGpfViAlPiUNCiAgbXV0YXRlKEluanVyeSA9IGNhc2Vfd2hlbigNCiAgICBHcm91cCA9PSAwIH4gJ05vbmUnLA0KICAgIEdyb3VwID09IDEgfiBJbmp1cnkuMS5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gMiB+IEluanVyeS4yLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSAzIH4gSW5qdXJ5LjMuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDQgfiBJbmp1cnkuNC5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNSB+IEluanVyeS41LkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA2IH4gSW5qdXJ5LjYuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDcgfiBJbmp1cnkuNy5EaWFnbm9zaXMsDQogICAgVFJVRSB+ICdBZnRlcicNCiAgKSwNCiAgQXJlYSA9IGNhc2Vfd2hlbigNCiAgICBHcm91cCA9PSAwIH4gJ05vbmUnLA0KICAgIEdyb3VwID09IDEgfiBJbmp1cnkuMS5BcmVhLA0KICAgIEdyb3VwID09IDIgfiBJbmp1cnkuMi5BcmVhLA0KICAgIEdyb3VwID09IDMgfiBJbmp1cnkuMy5BcmVhLA0KICAgIEdyb3VwID09IDQgfiBJbmp1cnkuNC5BcmVhLA0KICAgIEdyb3VwID09IDUgfiBJbmp1cnkuNS5BcmVhLA0KICAgIEdyb3VwID09IDYgfiBJbmp1cnkuNi5BcmVhLA0KICAgIEdyb3VwID09IDcgfiBJbmp1cnkuNy5BcmVhLA0KICAgIFRSVUUgfiAnQWZ0ZXInDQogICkpICU+JQ0KICBtdXRhdGUoV2FzLkluanVyZWQgPSBpZmVsc2UoR3JvdXAgPT0gMSB8IEdyb3VwID09IDIgfCBHcm91cCA9PSAzIHwgR3JvdXAgPT0gNCB8IEdyb3VwID09IDUgfCBHcm91cCA9PSA2IHwgR3JvdXAgPT0gNywgJ1llcycsIEdyb3VwKSkgJT4lDQogIGRwbHlyOjpzZWxlY3QoYW5vbl9pZCwgRGF0ZSwgQ29ycmVjdGVkLlN0YW5kaW5nLldlaWdodC4uS2cuLCBNZWFuLlJTSS4uRmxpZ2h0LkNvbnRhY3QuVGltZS4sIEFjdGl2ZS5TdGlmZm5lc3MuLk4ubS4sIEJlc3QuQXZlcmFnZS5Gb3JjZS4uTi4sIEJlc3QuQXZlcmFnZS5Gb3JjZS4uQXN5bS4uLk4uLCBCZXN0LlRpbWUudG8uUGVhay5Gb3JjZS4ubXMuLCBCZXN0LkNvbnRhY3QuVGltZS4ubXMuLCBCZXN0LkZsaWdodC5UaW1lLi5tcy4sIEJlc3QuSW1wdWxzZS4uTi5zLiwgQmVzdC5QZWFrLkZvcmNlLi5OLiwgQmVzdC5QZWFrLkZvcmNlLi5Bc3ltLi4uTi4sIE1lYW4uQXZlcmFnZS5Gb3JjZS4uTi4sIE1lYW4uQXZlcmFnZS5Gb3JjZS4uQXN5bS4uLk4uLCBNZWFuLkxhbmRpbmcuUkZELi5OLnMuLCBNZWFuLkxhbmRpbmcuUkZELi5Bc3ltLi4uTi5zLiwgU3RpZmZuZXNzLkZhdGlndWUuLi4uLCBTdGlmZm5lc3MuRmF0aWd1ZS4uQXN5bS4uLi4uLCBNYXguSnVtcC5IZWlnaHQuLmNtLiwgSW5qdXJ5LCBBcmVhLCBXYXMuSW5qdXJlZCwgU3BvcnQsIEhKLlJTSSwgTWVhbi5GbGlnaHQuVGltZS4ubXMuLCBNZWFuLkNvbnRhY3QuVGltZS4ubXMuKQ0KYGBgDQoNCioqSU1UUCBEYXRhKioNCg0KYGBge3J9DQojbWVyZ2VzIHRoZSBsYXN0X2luanVyeV9CIHRvIHRoZSBISl9CIGJ5IGFub25faWQNCm1lcmdlX2ltdHBfViA8LSBtZXJnZShsYXN0X2luanVyeV9WLCBJTVRQX1YsIGJ5ID0gYygnYW5vbl9pZCcpLCBhbGwgPSBUUlVFKQ0KDQojY3JlYXRlcyBhIHZhcmlhYmxlIGNhbGxlZCBHcm91cCB0aGF0IGdyb3VwcyBiYXNlZCBvbiBkYXRlIHdpdGhpbiBpbmp1cnkgaW50ZXJ2YWxzIGFuZCBvdXRwdXRzICdBZnRlcicgaWYgdGhlIGRhdGUgaXMgYWZ0ZXIgYWxsIGluanVyaWVzLCBhbmQgdGhlbiB0aGVzZSBhcmUgb21pdHRlZA0KbWVyZ2VfaW10cF9WIDwtIG1lcmdlX2ltdHBfViAlPiUNCiAgbXV0YXRlKEdyb3VwID0gY2FzZV93aGVuKA0KICAgIGlzLm5hKEluanVyeS4xKSB8IERhdGUgPCBJbmp1cnkuMS5TdGFydCB+ICcwJywNCiAgICAhaXMubmEoSW5qdXJ5LjEpICYgRGF0ZSA+PSBJbmp1cnkuMS5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjEgfiAnMScsDQogICAgIWlzLm5hKEluanVyeS4yKSAmIERhdGUgPj0gSW5qdXJ5LjIuU3RhcnQgJiBEYXRlIDw9IEluanVyeS4yIH4gJzInLA0KICAgICFpcy5uYShJbmp1cnkuMykgJiBEYXRlID49IEluanVyeS4zLlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuMyB+ICczJywNCiAgICAhaXMubmEoSW5qdXJ5LjQpICYgRGF0ZSA+PSBJbmp1cnkuNC5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjQgfiAnNCcsDQogICAgIWlzLm5hKEluanVyeS41KSAmIERhdGUgPj0gSW5qdXJ5LjUuU3RhcnQgJiBEYXRlIDw9IEluanVyeS41IH4gJzUnLA0KICAgICFpcy5uYShJbmp1cnkuNikgJiBEYXRlID49IEluanVyeS42LlN0YXJ0ICYgRGF0ZSA8PSBJbmp1cnkuNiB+ICc2JywNCiAgICAhaXMubmEoSW5qdXJ5LjcpICYgRGF0ZSA+PSBJbmp1cnkuNy5TdGFydCAmIERhdGUgPD0gSW5qdXJ5LjcgfiAnNycsDQogICAgVFJVRSB+ICdBZnRlcicpKSAlPiUNCiAgZmlsdGVyKEdyb3VwICE9ICdBZnRlcicpDQoNCiNjb25kZW5zZXMgb2JzZXJ2YXRpb25zIGJhc2VkIG9uIGdyb3VwIGFuZCBwbGF5ZXIgc3VtbWFyaXppbmcgbWVhbnMgb2YgdmFyaWFibGVzIG9mIGludGVyZXN0DQptZXJnZV9pbXRwX1YgPC0gbWVyZ2VfaW10cF9WICU+JQ0KICBtdXRhdGUoSW5qdXJ5ID0gY2FzZV93aGVuKA0KICAgIEdyb3VwID09IDAgfiAnTm9uZScsDQogICAgR3JvdXAgPT0gMSB+IEluanVyeS4xLkRpYWdub3NpcywNCiAgICBHcm91cCA9PSAyIH4gSW5qdXJ5LjIuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDMgfiBJbmp1cnkuMy5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNCB+IEluanVyeS40LkRpYWdub3NpcywNCiAgICBHcm91cCA9PSA1IH4gSW5qdXJ5LjUuRGlhZ25vc2lzLA0KICAgIEdyb3VwID09IDYgfiBJbmp1cnkuNi5EaWFnbm9zaXMsDQogICAgR3JvdXAgPT0gNyB+IEluanVyeS43LkRpYWdub3NpcywNCiAgICBUUlVFIH4gJ0FmdGVyJw0KICApLA0KICBBcmVhID0gY2FzZV93aGVuKA0KICAgIEdyb3VwID09IDAgfiAnTm9uZScsDQogICAgR3JvdXAgPT0gMSB+IEluanVyeS4xLkFyZWEsDQogICAgR3JvdXAgPT0gMiB+IEluanVyeS4yLkFyZWEsDQogICAgR3JvdXAgPT0gMyB+IEluanVyeS4zLkFyZWEsDQogICAgR3JvdXAgPT0gNCB+IEluanVyeS40LkFyZWEsDQogICAgR3JvdXAgPT0gNSB+IEluanVyeS41LkFyZWEsDQogICAgR3JvdXAgPT0gNiB+IEluanVyeS42LkFyZWEsDQogICAgR3JvdXAgPT0gNyB+IEluanVyeS43LkFyZWEsDQogICAgVFJVRSB+ICdBZnRlcicNCiAgKSkgJT4lDQogIG11dGF0ZShXYXMuSW5qdXJlZCA9IGlmZWxzZShHcm91cCA9PSAxIHwgR3JvdXAgPT0gMiB8IEdyb3VwID09IDMgfCBHcm91cCA9PSA0IHwgR3JvdXAgPT0gNSB8IEdyb3VwID09IDYgfCBHcm91cCA9PSA3LCAnWWVzJywgR3JvdXApKSAlPiUNCiAgZHBseXI6OnNlbGVjdChhbm9uX2lkLCBEYXRlLCBCYXNlbGluZS5Gb3JjZS4uTi4sIEJhc2VsaW5lLkZvcmNlLi5Bc3ltLi4uTi4sIFBlYWsuVmVydGljYWwuRm9yY2UuLk4uLCBQZWFrLlZlcnRpY2FsLkZvcmNlLi4uQk0uLk4ua2cuLCBQZWFrLlZlcnRpY2FsLkZvcmNlLi5Bc3ltLi4uTi4sIFJGRC4uLjUwbXMuLk4ucy4sIFJGRC4uLjUwbXMuLkFzeW0uLi5OLnMuLCBSRkQuLi4xMDBtcy4uTi5zLiwgUkZELi4uMTAwbXMuLkFzeW0uLi5OLnMuLCBSRkQuLi4xNTBtcy4uTi5zLiwgUkZELi4uMTUwbXMuLkFzeW0uLi5OLnMuLCBSRkQuLi4yMDBtcy4uTi5zLiwgUkZELi4uMjAwbXMuLkFzeW0uLi5OLnMuLCBOZXQuUGVhay5WZXJ0aWNhbC5Gb3JjZS4uTi5zLiwgTmV0LlBlYWsuVmVydGljYWwuRm9yY2UuLkFzeW0uLi5OLnMuLCBGb3JjZS5hdC4yMDBtcy4uLkJNLi5OLmtnLiwgSW5qdXJ5LCBBcmVhLCBXYXMuSW5qdXJlZCwgU3BvcnQpDQpgYGANCg0KIyMjIE1lcmdpbmcgQWxsIFBlcmZvcm1hbmNlIERhdGEgVG9nZXRoZXINCg0KKipOb3JkaWMgRGF0YSoqDQoNCmBgYHtyfQ0KI2NyZWF0aW5nIGEgZGF0YXNldCBjb250YWluaW5nIHBlcmZvcm1hbmNlIGRhdGEgYWNjcm9zcyBhbGwgc3BvcnRzDQpwZXJmb3JtYW5jZV9hbGxfaW5qdXJ5IDwtIHJiaW5kKG1lcmdlX3BlcmZvcm1hbmNlX0IsIG1lcmdlX3BlcmZvcm1hbmNlX1MsIG1lcmdlX3BlcmZvcm1hbmNlX0wsIG1lcmdlX3BlcmZvcm1hbmNlX1YpICU+JQ0KICBtdXRhdGUoVGhyZXNoID0gaWZlbHNlKFJlbGF0aXZlLk1heGltdW0uTm9yZGljLkJpbGF0ZXJhbC5NZWFuID49IDUsICdZZXMnLCAnTm8nKSwNCiAgICAgICAgIFNwb3J0LjIgPSBpZmVsc2UoU3BvcnQgPT0gJ0Jhc2tldGJhbGwnIHwgU3BvcnQgPT0gJ1ZvbGxleWJhbGwnLCAnQ291cnQnLCAnRmllbGQnKSkNCmBgYA0KDQoqKkhpcCBEYXRhKioNCg0KYGBge3J9DQojY3JlYXRpbmcgYSBkYXRhc2V0IGNvbnRhaW5pbmcgcGVyZm9ybWFuY2UgZGF0YSBhY2Nyb3NzIGFsbCBzcG9ydHMNCmhpcF9hbGxfaW5qdXJ5IDwtIHJiaW5kKG1lcmdlX2hpcF9CLCBtZXJnZV9oaXBfUywgbWVyZ2VfaGlwX0wsIG1lcmdlX2hpcF9WKSAlPiUNCiAgbXV0YXRlKEF2Zy5BYmQuTWVhbiA9IChIaXAuQWJkLkxlZnQuTUVBTiArIEhpcC5BYmQuUmlnaHQuTUVBTikgLyAyLA0KICAgICAgICAgQXZnLkFkZC5NZWFuID0gKEhpcC5BZGQuTGVmdC5NRUFOICsgSGlwLkFkZC5SaWdodC5NRUFOKSAvIDIsDQogICAgICAgICBBdmcuQWJkLk1heCA9IChIaXAuQWJkLkxlZnQuTUFYICsgSGlwLkFiZC5SaWdodC5NQVgpIC8gMiwNCiAgICAgICAgIEF2Zy5BZGQuTWF4ID0gKEhpcC5BZGQuTGVmdC5NQVggKyBIaXAuQWRkLlJpZ2h0Lk1BWCkgLyAyLA0KICAgICAgICAgUmVsYXRpdmUuQWJkLk1lYW4gPSBBdmcuQWJkLk1lYW4gLyBBdGhsZXRlLkJvZHl3ZWlnaHQuLmtnLiwNCiAgICAgICAgIFJlbGF0aXZlLkFkZC5NZWFuID0gQXZnLkFkZC5NZWFuIC8gQXRobGV0ZS5Cb2R5d2VpZ2h0Li5rZy4sDQogICAgICAgICBSZWxhdGl2ZS5BYmQuTWF4ID0gQXZnLkFiZC5NYXggLyBBdGhsZXRlLkJvZHl3ZWlnaHQuLmtnLiwNCiAgICAgICAgIFJlbGF0aXZlLkFkZC5NYXggPSBBdmcuQWRkLk1heCAvIEF0aGxldGUuQm9keXdlaWdodC4ua2cuLA0KICAgICAgICAgU3BvcnQuMiA9IGlmZWxzZShTcG9ydCA9PSAnQmFza2V0YmFsbCcgfCBTcG9ydCA9PSAnVm9sbGV5YmFsbCcsICdDb3VydCcsICdGaWVsZCcpKQ0KYGBgDQoNCioqSEogRGF0YSoqDQoNCmBgYHtyfQ0KI2NyZWF0aW5nIGEgZGF0YXNldCBjb250YWluaW5nIHBlcmZvcm1hbmNlIGRhdGEgYWNjcm9zcyBhbGwgc3BvcnRzDQpoal9hbGxfaW5qdXJ5IDwtIHJiaW5kKG1lcmdlX2hqX0IsIG1lcmdlX2hqX1MsIG1lcmdlX2hqX0wsIG1lcmdlX2hqX1YpICU+JQ0KICBtdXRhdGUoU3BvcnQuMiA9IGlmZWxzZShTcG9ydCA9PSAnQmFza2V0YmFsbCcgfCBTcG9ydCA9PSAnVm9sbGV5YmFsbCcsICdDb3VydCcsICdGaWVsZCcpLA0KICAgICAgICAgV2FzLkluanVyZWQgPSBpZmVsc2UoV2FzLkluanVyZWQgPT0gJ1llcycsICdZZXMnLCAnTm8nKSwNCiAgICAgICAgIEFua2xlID0gaWZlbHNlKEFyZWEgPT0gJ0Fua2xlJywgJ1llcycsICdObycpLA0KICAgICAgICAgS25lZSA9IGlmZWxzZShBcmVhID09ICdLbmVlJywgJ1llcycsICdObycpKQ0KDQpmaWVsZF9hbmtsZSA8LSBoal9hbGxfaW5qdXJ5ICU+JQ0KICBmaWx0ZXIoU3BvcnQuMiA9PSAnRmllbGQnICYgQXJlYSAlaW4lIGMoJ0Fua2xlJywgJ05vbmUnKSkgJT4lDQogIG11dGF0ZShXYXMuSW5qdXJlZC4gPSBhcy5mYWN0b3IoaWZlbHNlKFdhcy5Jbmp1cmVkID09ICdZZXMnLCAxLCAwKSkpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGZpZWxkX2Fua2xlLCBhZXMoTWF4Lkp1bXAuSGVpZ2h0Li5jbS4sIGZpbGwgPSBXYXMuSW5qdXJlZCkpICsgDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCcjQ0ZCODdDJywgJyMwMDAwMDAnKSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAyMS41NzI1LCBjb2xvciA9ICdyZWQnLCBsaW5ldHlwZSA9ICdkYXNoZWQnKSArDQogIGxhYnModGl0bGUgPSAnTWF4IEp1bXAgSGVpZ2h0IHZzIEFua2xlIEluanVyeScsDQogICAgICAgeCA9ICdNYXggSnVtcCBIZWlnaHQgKGNtKScsDQogICAgICAgeSA9ICdEZW5zaXR5JywNCiAgICAgICBmaWxsID0gJ0Fua2xlIEluanVyeScsDQogICAgICAgY2FwdGlvbiA9ICdDVSBXb21lbnMgU29jY2VyIGFuZCBMYWNyb3NzZScpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCA1MCwgNCkpICsgDQogIHRoZW1lX2J3KCkNCmBgYA0KDQpgYGB7cn0NCnJvY19vYmogPC0gcm9jKHJlc3BvbnNlID0gZmllbGRfYW5rbGUkV2FzLkluanVyZWQsIHByZWRpY3RvciA9IGZpZWxkX2Fua2xlJE1heC5KdW1wLkhlaWdodC4uY20uLCBkaXJlY3Rpb24gPSAiPiIpDQoNCnBsb3Qocm9jX29iaiwgcHJpbnQuYXVjID0gVFJVRSwgY29sID0gIiNDRkI4N0MiLCBtYWluID0gIlJPQyBDdXJ2ZSBmb3IgVHJhaW5pbmcgTG9hZCIpDQpgYGANCg0KYGBge3J9DQpyb2NfY29vcmRzIDwtIGNvb3Jkcyhyb2Nfb2JqLCB4ID0gImJlc3QiLCBiZXN0Lm1ldGhvZCA9ICJ5b3VkZW4iLCByZXQgPSBjKCJ0aHJlc2hvbGQiLCAic2Vuc2l0aXZpdHkiLCAic3BlY2lmaWNpdHkiKSkNCg0KcHJpbnQocm9jX2Nvb3JkcykNCmBgYA0KDQpgYGB7cn0NCm1vZGVsIDwtIGdsbShXYXMuSW5qdXJlZC4gfiBNZWFuLkNvbnRhY3QuVGltZS4ubXMuLCBkYXRhID0gZmllbGRfYW5rbGUsIGZhbWlseSA9ICdiaW5vbWlhbCcpDQoNCnN1bW1hcnkobW9kZWwpDQpgYGANCg0KDQojUTI6V2hhdCB0cmVuZHMgaW4gc3RyZW5ndGggZG8gd2Ugc2VlIGFjcm9zcyB0aGUgd29tZW7igJlzIHRlYW0gc3BvcnRzPyANCmEuIFNvY2NlciwgbGFjcm9zc2UsIHZvbGxleWJhbGwsIGJhc2tldGJhbGwuDQpgYGB7cn0NCiNyZWxvYWQgZGF0YXNldHMNCkluY2lkZW50X0IgPC0gcmVhZC5jc3YoIn4vVDJQMi1kYXRhLWFuYWx5c2lzLTIwMjUvZGF0YS1zZXRzL0luY2lkZW50IFJlcG9ydCBXQkIuY3N2IikNCkluY2lkZW50X1MgPC0gcmVhZC5jc3YoIn4vVDJQMi1kYXRhLWFuYWx5c2lzLTIwMjUvZGF0YS1zZXRzL0luY2lkZW50IFJlcG9ydCBXU09DLmNzdiIpDQpJbmNpZGVudF9MIDwtIHJlYWQuY3N2KCJ+L1QyUDItZGF0YS1hbmFseXNpcy0yMDI1L2RhdGEtc2V0cy9JbmNpZGVudCBSZXBvcnQgV0xBWC5jc3YiKQ0KSW5jaWRlbnRfViA8LSByZWFkLmNzdigifi9UMlAyLWRhdGEtYW5hbHlzaXMtMjAyNS9kYXRhLXNldHMvSW5jaWRlbnQgUmVwb3J0IFdWQi5jc3YiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBjb3VudCAjIG9mIHdoYXQgdHlwZSBvZiBpbmp1cmllcyBpbiBlYWNoIHNwb3J0IA0KY291bnRfY2F0ZWdvcmllcyA8LSBmdW5jdGlvbihkYXRhLCBjb2x1bW5fbmFtZSkgew0KICBkYXRhIHw+DQogICAgZHBseXI6OmNvdW50KC5kYXRhW1tjb2x1bW5fbmFtZV1dKSB8Pg0KICAgIGRwbHlyOjphcnJhbmdlKGRlc2MobikpDQp9DQpJbmNpZGVudF9CIDwtIEluY2lkZW50X0IgJT4lDQogIGZpbHRlcihCb2R5LlBhcnQuICVpbiUgYygiVGhpZ2giLCAiQW5rbGUiLCAiTG93ZXIgbGVnIiwgIktuZWUiLCAiRm9vdCIsICJHcm9pbi9oaXAiKSkNCkluY2lkZW50X1MgPC0gSW5jaWRlbnRfUyAlPiUNCiAgZmlsdGVyKEJvZHkuUGFydC4gJWluJSBjKCJUaGlnaCIsICJBbmtsZSIsICJMb3dlciBsZWciLCAiS25lZSIsICJGb290IiwgIkdyb2luL2hpcCIpKQ0KSW5jaWRlbnRfViA8LSBJbmNpZGVudF9WICU+JQ0KICBmaWx0ZXIoQm9keS5QYXJ0LiAlaW4lIGMoIlRoaWdoIiwgIkFua2xlIiwgIkxvd2VyIGxlZyIsICJLbmVlIiwgIkZvb3QiLCAiR3JvaW4vaGlwIikpDQpJbmNpZGVudF9MIDwtIEluY2lkZW50X0wgJT4lDQogIGZpbHRlcihCb2R5LlBhcnQuICVpbiUgYygiVGhpZ2giLCAiQW5rbGUiLCAiTG93ZXIgbGVnIiwgIktuZWUiLCAiRm9vdCIsICJHcm9pbi9oaXAiKSkNCg0KI2NvbnZlcnQgdG8gY2hhcmFjdGVyDQpJbmNpZGVudF9CJEJvZHkuUGFydC4gPC0gYXMuY2hhcmFjdGVyKEluY2lkZW50X0IkQm9keS5QYXJ0LikNCkluY2lkZW50X1MkQm9keS5QYXJ0LiA8LSBhcy5jaGFyYWN0ZXIoSW5jaWRlbnRfUyRCb2R5LlBhcnQuKQ0KSW5jaWRlbnRfViRCb2R5LlBhcnQuIDwtIGFzLmNoYXJhY3RlcihJbmNpZGVudF9WJEJvZHkuUGFydC4pDQpJbmNpZGVudF9MJEJvZHkuUGFydC4gPC0gYXMuY2hhcmFjdGVyKEluY2lkZW50X0wkQm9keS5QYXJ0LikNCg0KY291bnRfY2F0ZWdvcmllcyhJbmNpZGVudF9CLCAiQm9keS5QYXJ0LiIpDQpjb3VudF9jYXRlZ29yaWVzKEluY2lkZW50X1MsICJCb2R5LlBhcnQuIikNCmNvdW50X2NhdGVnb3JpZXMoSW5jaWRlbnRfViwgIkJvZHkuUGFydC4iKQ0KY291bnRfY2F0ZWdvcmllcyhJbmNpZGVudF9MLCAiQm9keS5QYXJ0LiIpDQpgYGANCg0KYGBge3J9DQojY291bnQgb2YgYWxsIGRpZmZlcmVudCB0ZXN0IHR5cGVzIGJ5IHNwb3J0IA0KY291bnRfY2F0ZWdvcmllcyhGb3JjZWRlY2tzX0IsICJUZXN0LlR5cGUiKQ0KY291bnRfY2F0ZWdvcmllcyhGb3JjZWRlY2tzX1MsICJUZXN0LlR5cGUiKQ0KY291bnRfY2F0ZWdvcmllcyhGb3JjZWRlY2tzX1YsICJUZXN0LlR5cGUiKQ0KY291bnRfY2F0ZWdvcmllcyhGb3JjZWRlY2tzX0wsICJUZXN0LlR5cGUiKQ0KYGBgDQoNCiMjRm9yY2VkZWNrcw0KYGBge3J9DQojbWFrZSBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlIGluY2x1ZGluZyBlYWNoIGluanVyeSB0byBwbG90IHRvZ2V0aGVyICANCiMxPSBMQi5Jbmp1cnksIDI9SFNJLCAzPUFDTA0KYWxsX2luY2lkZW50JEluanVyeVR5cGUgPC0gd2l0aChhbGxfaW5jaWRlbnQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoQUNMID09IDEsICJBQ0wiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoSFNJID09IDEsICJIU0kiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoTEIuSW5qdXJ5ICA9PSAxLCAiTG93ZXIgYm9keSIsIE5BKSkpKQ0KDQojY29udmVydCB0byBmYWN0b3IgDQphbGxfaW5jaWRlbnQkSW5qdXJ5VHlwZSA8LSBmYWN0b3IoYWxsX2luY2lkZW50JEluanVyeVR5cGUsIGxldmVscyA9IGMoIkxvd2VyIGJvZHkiLCAiSFNJIiwgIkFDTCIpKQ0KDQogI25vdyBpbiBkYXRhIG9ubHkga2VlcCB0aG9zZSAzIGluanVyaWVzDQphbGxfaW5jaWQgPC0gYWxsX2luY2lkZW50W2FsbF9pbmNpZGVudCRCb2R5LlBhcnQuICVpbiUgYygiVGhpZ2giLCAiQW5rbGUiLCAiTG93ZXIgbGVnIiwgIktuZWUiLCAiRm9vdCIsICJHcm9pbi9oaXAiKSxdDQpgYGANCg0KYGBge3J9DQojcGxvdCBjb3VudCBvbiB5IGF4aXMsIHRoZW4geD0gZWFjaCBzcG9ydCAsIGZpbGwgZWFjaCBpbmp1cnkgDQogIGdncGxvdChkYXRhPWFsbF9pbmNpZCwgYWVzKHg9U3BvcnQsIGZpbGw9SW5qdXJ5VHlwZSkpKw0KICBnZW9tX2JhcihuYS5ybT1UUlVFKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJMb3dlciBib2R5Ij0nI0NGQjg3QycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJIU0kiPSd3aGl0ZScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBQ0wiPSdibGFjaycpKSArDQogIGxhYnModGl0bGU9IlRoZSBOdW1iZXIgb2YgRWFjaCBJbmp1cnkgYnkgU3BvcnQiLA0KICAgICAgIHk9IkNvdW50IiwNCiAgICAgICB4PSJTcG9ydCIsDQogICAgICAgZmlsbD0iSW5qdXJ5IFR5cGUiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCmBgYHtyfQ0KI3JlY3VycmVuY2Ugb2YgaW5qdXJ5IHBsb3QgDQpnZ3Bsb3QoYWxsX2luY2lkLCBhZXMoeD1TcG9ydCwgZmlsbD1SZWN1cnJlbmNlLm9mLkluanVyeSkpKw0KICBnZW9tX2JhcihuYS5ybT1UUlVFKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJOZXcgSW5qdXJ5L0lsbG5lc3MiPScjQ0ZCODdDJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZpcnN0IHJlY3VycmVuY2UiPSdibGFjaycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNdWx0aXBsZSByZWN1cnJlbmNlIj0nd2hpdGUnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUHJlLWV4aXN0aW5nIGluanVyeS9pbGxuZXNzIj0gJ2dyZXknKSkgKw0KICBsYWJzKHRpdGxlPSJUaGUgTnVtYmVyIG9mIEVhY2ggSW5qdXJ5IFJlY3VycmVuY2UgYnkgU3BvcnQiLA0KICAgICAgIHk9IkNvdW50IiwNCiAgICAgICB4PSJTcG9ydCIsDQogICAgICAgZmlsbD0iUmVjdXJyZW5jZSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiNEU0kgYnVja2V0IHBsb3QgDQpnZ3Bsb3QoYWxsX0lNVFBfaW5jaWRlbnQsIGFlcyh4PVNwb3J0LCBmaWxsPURTSS5CdWNrZXQpKSsNCiAgZ2VvbV9iYXIobmEucm09VFJVRSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiTWF4aW1hbCBTdHJlbmd0aCBUcmFpbmluZyI9J2JsYWNrJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNvbmN1cnJlbnQgVHJhaW5pbmciPSd3aGl0ZScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCYWxsaXN0aWMgU3RyZW5ndGggVHJhaW5pbmciPScjQ0ZCODdDJykpICsNCiAgbGFicyh0aXRsZT0iVGhlIE51bWJlciBvZiBFYWNoIERTSSBCdWNrZXQgYnkgU3BvcnQiLA0KICAgICAgIHk9IkNvdW50IiwNCiAgICAgICB4PSJTcG9ydCIsDQogICAgICAgZmlsbD0iRFNJIEJ1Y2tldCIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCkFzIHNlZW4gaW4gdGhlIHBhc3QgcHJvamVjdCB3aXRoIHRoZSBmb290YmFsbCBkYXRhLCB0aGUgbWFpbiB0eXBlIG9mIGluanVyeSBpcyBhIG5ldyBpbmp1cnksIHdoaWNoIG1ha2VzIGl0IG11Y2ggaGFyZGVyIHRvIHByZXZlbnQgb3IgcHJlZGljdC4gQWNyb3NzIGFsbCBvZiB0aGUgd29tZW5zIHNwb3J0cyB0aGVpciBmb2N1cyBpcyBvbiBiYWxsaXN0aWMgc3RyZW5ndGggdHJhaW5pbmcgd2hpY2ggZW1waGFzaXplcyBzcGVlZCBhbmQgZXhwbG9zaXZlbmVzcy4NCg0KI0VhY2ggU3BvcnRzIEluZGl2aWR1YWwgQXRobGV0ZXMgSW5qdXJpZXMgT3ZlciB0aW1lDQpgYGB7cn0NCiNmaWx0ZXIgbGFjcm9zc2UgaW5jaWRlbnQgZGF0YSBmb3IgcGxvdHMgDQppbmp1cnlfbF9jdW11bGF0aXZlIDwtIGluY2lkZW50X2wgJT4lDQogIGZpbHRlcihTdGF0dXM9PSJPdXQiKSAlPiUNCiAgYXJyYW5nZShhbm9uX2lkLCBTdGFydC5vZi5TdGF0dXMpICU+JQ0KICBncm91cF9ieShhbm9uX2lkKSAlPiUNCiAgbXV0YXRlKEN1bXVsYXRpdmVJbmp1cmllcyA9IHJvd19udW1iZXIoKSkgDQoNCiNsaW5lIGdyYXBoIA0KZ2dwbG90KGluanVyeV9sX2N1bXVsYXRpdmUsYWVzKHggPUN1bXVsYXRpdmVJbmp1cmllcyAseSA9IFN0YXJ0Lm9mLlN0YXR1cyxjb2xvciA9IGFzLmZhY3Rvcihhbm9uX2lkKSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBsYWJzKHggPSAiQ3VtdWxhdGl2ZSBJbmp1cmllcyBwZXIgQXRobGV0ZSIsIHkgPSAiSW5qdXJ5IFRpbWUgUGVyaW9kIiwgY29sb3IgPSAiQXRobGV0ZSBJRCIpICsNCiAgI3hsaW0oMCw1KSsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDAsMSwyLDMsNCw1KSkrDQogIHRoZW1lX21pbmltYWwoKQ0KZ2dwbG90KGluanVyeV9sX2N1bXVsYXRpdmUsYWVzKHggPVN0YXJ0Lm9mLlN0YXR1cyAseSA9IEN1bXVsYXRpdmVJbmp1cmllcyxjb2xvciA9IGFzLmZhY3Rvcihhbm9uX2lkKSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBsYWJzKHggPSAiSW5qdXJ5IFRpbWUgUGVyaW9kIiwgeSA9ICJDdW11bGF0aXZlIEluanVyaWVzIHBlciBBdGhsZXRlIiwgY29sb3IgPSAiQXRobGV0ZSBJRCIpICsNCiAjIHlsaW0oMCw1KSsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1jKDAsMSwyLDMsNCw1KSkrDQogIHRoZW1lX21pbmltYWwoKQ0KI2ZpZ3VyZSBvdXQgaG93IHRvIGdldCBpdCB0byBzdGFydCBhdCAwIGFuZCBzaG93IG90aGVyIGxpbmVzDQoNCiNiYXIgcGxvdCANCmdncGxvdChpbmp1cnlfbF9jdW11bGF0aXZlLCBhZXMoeCA9IFN0YXJ0Lm9mLlN0YXR1cywgeSA9IEN1bXVsYXRpdmVJbmp1cmllcywgZ3JvdXAgPSBhbm9uX2lkKSkgKw0KICBnZW9tX3NlZ21lbnQoYWVzKHhlbmQgPSBFbmQuRGF0ZSwgeWVuZCA9IEN1bXVsYXRpdmVJbmp1cmllcywgY29sb3IgPSBhbm9uX2lkKSwgc2l6ZSA9IDIpICsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBhbm9uX2lkKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPWMoMCwxLDIsMyw0LDUpKSsNCiAgbGFicyh4ID0gIkluanVyeSBUaW1lIFBlcmlvZCIsIHkgPSAiQ3VtdWxhdGl2ZSBJbmp1cmllcyBwZXIgQXRobGV0ZSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3J9DQojZmlsdGVyIGJhc2tldGJhbGwgaW5jaWRlbnQgZGF0YSBmb3IgcGxvdHMgDQppbmp1cnlfYl9jdW11bGF0aXZlIDwtIGluY2lkZW50X2IgJT4lDQogIGZpbHRlcihTdGF0dXM9PSJPdXQiKSAlPiUNCiAgYXJyYW5nZShhbm9uX2lkLCBTdGFydC5vZi5TdGF0dXMpICU+JQ0KICBncm91cF9ieShhbm9uX2lkKSAlPiUNCiAgbXV0YXRlKEN1bXVsYXRpdmVJbmp1cmllcyA9IHJvd19udW1iZXIoKSkgDQoNCiNsaW5lIGdyYXBoIA0KZ2dwbG90KGluanVyeV9iX2N1bXVsYXRpdmUsYWVzKHggPUN1bXVsYXRpdmVJbmp1cmllcyAseSA9IFN0YXJ0Lm9mLlN0YXR1cyxjb2xvciA9IGFzLmZhY3Rvcihhbm9uX2lkKSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBsYWJzKHggPSAiQ3VtdWxhdGl2ZSBJbmp1cmllcyBwZXIgQXRobGV0ZSIsIHkgPSAiSW5qdXJ5IFRpbWUgUGVyaW9kIiwgY29sb3IgPSAiQXRobGV0ZSBJRCIpICsNCiAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygwLDEsMiwzLDQsNSkpKw0KICAjeGxpbSgwLDUpKw0KICB0aGVtZV9taW5pbWFsKCkNCmdncGxvdChpbmp1cnlfYl9jdW11bGF0aXZlLGFlcyh4ID1TdGFydC5vZi5TdGF0dXMgLHkgPSBDdW11bGF0aXZlSW5qdXJpZXMsY29sb3IgPSBhcy5mYWN0b3IoYW5vbl9pZCkpKSArDQogIGdlb21fbGluZSgpICsNCiAgbGFicyh4ID0gIkluanVyeSBUaW1lIFBlcmlvZCIsIHkgPSAiQ3VtdWxhdGl2ZSBJbmp1cmllcyBwZXIgQXRobGV0ZSIsIGNvbG9yID0gIkF0aGxldGUgSUQiKSArDQogICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPWMoMCwxLDIsMyw0LDUpKSsNCiAgI3lsaW0oMCw1KSsNCiAgdGhlbWVfbWluaW1hbCgpDQojZmlndXJlIG91dCBob3cgdG8gZ2V0IGl0IHRvIHN0YXJ0IGF0IDAgYW5kIHNob3cgb3RoZXIgbGluZXMNCg0KI2JhciBwbG90IA0KZ2dwbG90KGluanVyeV9iX2N1bXVsYXRpdmUsIGFlcyh4ID0gU3RhcnQub2YuU3RhdHVzLCB5ID0gQ3VtdWxhdGl2ZUluanVyaWVzLCBncm91cCA9IGFub25faWQpKSArDQogIGdlb21fc2VnbWVudChhZXMoeGVuZCA9IEVuZC5EYXRlLCB5ZW5kID0gQ3VtdWxhdGl2ZUluanVyaWVzLCBjb2xvciA9IGFub25faWQpLCBzaXplID0gMikgKw0KICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGFub25faWQpKSArDQogICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPWMoMCwxLDIsMyw0LDUpKSsNCiAgbGFicyh4ID0gIkluanVyeSBUaW1lIFBlcmlvZCIsIHkgPSAiQ3VtdWxhdGl2ZSBJbmp1cmllcyBwZXIgQXRobGV0ZSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3J9DQojZmlsdGVyIHNvY2NlciBpbmNpZGVudCBkYXRhIGZvciBwbG90cyANCmluanVyeV9zX2N1bXVsYXRpdmUgPC0gaW5jaWRlbnRfcyAlPiUNCiAgZmlsdGVyKFN0YXR1cz09Ik91dCIpICU+JQ0KICBhcnJhbmdlKGFub25faWQsIFN0YXJ0Lm9mLlN0YXR1cykgJT4lDQogIGdyb3VwX2J5KGFub25faWQpICU+JQ0KICBtdXRhdGUoQ3VtdWxhdGl2ZUluanVyaWVzID0gcm93X251bWJlcigpKSANCg0KI2xpbmUgZ3JhcGggDQpnZ3Bsb3QoaW5qdXJ5X3NfY3VtdWxhdGl2ZSxhZXMoeCA9Q3VtdWxhdGl2ZUluanVyaWVzICx5ID0gU3RhcnQub2YuU3RhdHVzLGNvbG9yID0gYXMuZmFjdG9yKGFub25faWQpKSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGxhYnMoeCA9ICJDdW11bGF0aXZlIEluanVyaWVzIHBlciBBdGhsZXRlIiwgeSA9ICJJbmp1cnkgVGltZSBQZXJpb2QiLCBjb2xvciA9ICJBdGhsZXRlIElEIikgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMCwxLDIsMyw0KSkrDQogICN4bGltKDAsNSkrDQogIHRoZW1lX21pbmltYWwoKQ0KZ2dwbG90KGluanVyeV9zX2N1bXVsYXRpdmUsYWVzKHggPVN0YXJ0Lm9mLlN0YXR1cyAseSA9IEN1bXVsYXRpdmVJbmp1cmllcyxjb2xvciA9IGFzLmZhY3Rvcihhbm9uX2lkKSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBsYWJzKHggPSAiSW5qdXJ5IFRpbWUgUGVyaW9kIiwgeSA9ICJDdW11bGF0aXZlIEluanVyaWVzIHBlciBBdGhsZXRlIiwgY29sb3IgPSAiQXRobGV0ZSBJRCIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1jKDAsMSwyLDMsNCkpKw0KICAjeWxpbSgwLDUpKw0KICB0aGVtZV9taW5pbWFsKCkNCiNmaWd1cmUgb3V0IGhvdyB0byBnZXQgaXQgdG8gc3RhcnQgYXQgMCBhbmQgc2hvdyBvdGhlciBsaW5lcw0KDQojYmFyIHBsb3QgDQpnZ3Bsb3QoaW5qdXJ5X3NfY3VtdWxhdGl2ZSwgYWVzKHggPSBTdGFydC5vZi5TdGF0dXMsIHkgPSBDdW11bGF0aXZlSW5qdXJpZXMsIGdyb3VwID0gYW5vbl9pZCkpICsNCiAgZ2VvbV9zZWdtZW50KGFlcyh4ZW5kID0gRW5kLkRhdGUsIHllbmQgPSBDdW11bGF0aXZlSW5qdXJpZXMsIGNvbG9yID0gYW5vbl9pZCksIHNpemUgPSAyKSArDQogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gYW5vbl9pZCkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1jKDAsMSwyLDMsNCkpKw0KICBsYWJzKHggPSAiSW5qdXJ5IFRpbWUgUGVyaW9kIiwgeSA9ICJDdW11bGF0aXZlIEluanVyaWVzIHBlciBBdGhsZXRlIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7cn0NCiNmaWx0ZXIgdm9sbGV5YmFsbCBpbmNpZGVudCBkYXRhIGZvciBwbG90cyANCmluanVyeV92X2N1bXVsYXRpdmUgPC0gaW5jaWRlbnRfdiAlPiUNCiAgZmlsdGVyKFN0YXR1cz09Ik91dCIpICU+JQ0KICBhcnJhbmdlKGFub25faWQsIFN0YXJ0Lm9mLlN0YXR1cykgJT4lDQogIGdyb3VwX2J5KGFub25faWQpICU+JQ0KICBtdXRhdGUoQ3VtdWxhdGl2ZUluanVyaWVzID0gcm93X251bWJlcigpKSANCg0KI2xpbmUgZ3JhcGggDQpnZ3Bsb3QoaW5qdXJ5X3ZfY3VtdWxhdGl2ZSxhZXMoeCA9Q3VtdWxhdGl2ZUluanVyaWVzICx5ID0gU3RhcnQub2YuU3RhdHVzLGNvbG9yID0gYXMuZmFjdG9yKGFub25faWQpKSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGxhYnMoeCA9ICJDdW11bGF0aXZlIEluanVyaWVzIHBlciBBdGhsZXRlIiwgeSA9ICJJbmp1cnkgVGltZSBQZXJpb2QiLCBjb2xvciA9ICJBdGhsZXRlIElEIikgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMCwxLDIsMykpKw0KICAjeGxpbSgwLDUpKw0KICB0aGVtZV9taW5pbWFsKCkNCmdncGxvdChpbmp1cnlfdl9jdW11bGF0aXZlLGFlcyh4ID1TdGFydC5vZi5TdGF0dXMgLHkgPSBDdW11bGF0aXZlSW5qdXJpZXMsY29sb3IgPSBhcy5mYWN0b3IoYW5vbl9pZCkpKSArDQogIGdlb21fbGluZSgpICsNCiAgbGFicyh4ID0gIkluanVyeSBUaW1lIFBlcmlvZCIsIHkgPSAiQ3VtdWxhdGl2ZSBJbmp1cmllcyBwZXIgQXRobGV0ZSIsIGNvbG9yID0gIkF0aGxldGUgSUQiKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9YygwLDEsMiwzKSkrDQogIyB5bGltKDAsNSkrDQogIHRoZW1lX21pbmltYWwoKQ0KI2ZpZ3VyZSBvdXQgaG93IHRvIGdldCBpdCB0byBzdGFydCBhdCAwIGFuZCBzaG93IG90aGVyIGxpbmVzDQoNCiNiYXIgcGxvdCANCmdncGxvdChpbmp1cnlfdl9jdW11bGF0aXZlLCBhZXMoeCA9IFN0YXJ0Lm9mLlN0YXR1cywgeSA9IEN1bXVsYXRpdmVJbmp1cmllcywgZ3JvdXAgPSBhbm9uX2lkKSkgKw0KICBnZW9tX3NlZ21lbnQoYWVzKHhlbmQgPSBFbmQuRGF0ZSwgeWVuZCA9IEN1bXVsYXRpdmVJbmp1cmllcywgY29sb3IgPSBhbm9uX2lkKSwgc2l6ZSA9IDIpICsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBhbm9uX2lkKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPWMoMCwxLDIsMykpKw0KICBsYWJzKHggPSAiSW5qdXJ5IFRpbWUgUGVyaW9kIiwgeSA9ICJDdW11bGF0aXZlIEluanVyaWVzIHBlciBBdGhsZXRlIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQoNCiNGb3JjZWRlY2tzIFN0cmVuZ3RoIFRyZW5kcyBTcG9ydCB0byBTcG9ydA0KMS4gQ01KICsgSW5jaWRlbnQgDQpgYGB7cn0NCmFsbF9DTUpfaW5jaWRlbnQgPC0gYWxsX0NNSl9pbmNpZGVudCAlPiUNCiBtdXRhdGUoVGhyZXNoID0gaWZlbHNlKFJlbGF0aXZlLkNvbmNlbnRyaWMuUG93ZXIuQmlsYXRlcmFsID49IDAuNSwgJ1llcycsICdObycpKQ0KDQojdGFibGUgd2l0aCBsb3dlciBib2R5IGluanVyeSBvbiBsZWZ0IGFuZCB3aGV0aGVyIHRoZSBvYnNlcnZhdGlvbiBpcyBhYm92ZS9iZWxvdyB0aHJlc2hvbGQNCnRhYmxlKGFsbF9DTUpfaW5jaWRlbnQkTEIuSW5qdXJ5LCBhbGxfQ01KX2luY2lkZW50JFRocmVzaCkNCg0KI2JveHBsb3QNCmdncGxvdChhbGxfQ01KX2luY2lkZW50LCBhZXMoeCA9IFJlbGF0aXZlLkNvbmNlbnRyaWMuUG93ZXIuQmlsYXRlcmFsLCB5ID0gU3BvcnQpKSArDQogIGdlb21fYm94cGxvdChmaWxsID0gJyNDRkI4N0MnLCBjb2xvciA9ICdibGFjaycpICsgDQogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIFJlbGF0aXZlIENvbmNlbnRyaWMgQmlsYXRlcmFsIFBvd2VyIEFjcm9zcyBTcG9ydHMnLA0KICAgICAgIHkgPSAnU3BvcnQnLA0KICAgICAgIHggPSAnUmVsYXRpdmUgQ29uY2VudHJpYyBCaWxhdGVyYWwgUG93ZXInKSArDQogIHRoZW1lX2J3KCkNCmBgYA0KDQpgYGB7cn0NCiNkZW5zaXR5IHBsb3QgDQpnZ3Bsb3QoYWxsX0NNSl9pbmNpZGVudCwgYWVzKHggPSBFY2NlbnRyaWMuQ29uY2VudHJpYy5NZWFuLkZvcmNlLlJhdGlvLCBmaWxsID0gU3BvcnQpKSArDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNCkgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygnI0NGQjg3QycsICcjNjY2NjY2JywgJyMwMDAwMDAnLCAnIzhDNzg1MycpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCcjQ0ZCODdDJywgJyM2NjY2NjYnLCAnIzAwMDAwMCcsICcjOEM3ODUzJykpICsNCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgRWNjZW50cmljIENvbmNlbnRyaWMgTWVhbiBGb3JjZSBSYXRpbyBBY3Jvc3MgU3BvcnRzJywNCiAgICAgICB4ID0gJ0VjY2VudHJpYyBDb25jZW50cmljIE1lYW4gRm9yY2UgUmF0aW8nLA0KICAgICAgIHkgPSAnRGVuc2l0eScpICsNCiAgdGhlbWVfYncoKQ0KDQojYW5vdmEgdGVzdCBmb3IgZGlmZmVyZW5jZXMNCmFub3ZhX3Jlc3VsdCA8LSBhb3YoRWNjZW50cmljLkNvbmNlbnRyaWMuTWVhbi5Gb3JjZS5SYXRpbyB+IFNwb3J0LCBkYXRhID0gYWxsX0NNSl9pbmNpZGVudCkNCnN1bW1hcnkoYW5vdmFfcmVzdWx0KQ0KYGBgDQoNCmBgYHtyfQ0KYWxsX0NNSl9pbmNpZGVudCA8LSBhbGxfQ01KX2luY2lkZW50ICU+JQ0KIG11dGF0ZShUaHJlc2gwID0gaWZlbHNlKE1heC5KdW1wLkhlaWdodC4uY20uID49IDAuNSwgJ1llcycsICdObycpKQ0KDQojdGFibGUgd2l0aCBsb3dlciBib2R5IGluanVyeSBvbiBsZWZ0IGFuZCB3aGV0aGVyIHRoZSBvYnNlcnZhdGlvbiBpcyBhYm92ZS9iZWxvdyB0aHJlc2hvbGQNCnRhYmxlKGFsbF9DTUpfaW5jaWRlbnQkTEIuSW5qdXJ5LCBhbGxfQ01KX2luY2lkZW50JFRocmVzaDApDQoNCiNib3hwbG90IA0KZ2dwbG90KGFsbF9DTUpfaW5jaWRlbnQsIGFlcyh4ID0gTWF4Lkp1bXAuSGVpZ2h0Li5jbS4sIHkgPSBTcG9ydCkpICsNCiAgZ2VvbV9ib3hwbG90KGZpbGwgPSAnI0NGQjg3QycsIGNvbG9yID0gJ2JsYWNrJykgKyANCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgTWF4aW11bSBKdW1wIEhlaWdodCBBY3Jvc3MgU3BvcnRzJywNCiAgICAgICB5ID0gJ1Nwb3J0JywNCiAgICAgICB4ID0gJ01heGltdW0gSnVtcCBIZWlnaHQgKGNtKScpICsNCiAgdGhlbWVfYncoKQ0KDQojZGVuc2l0eSBwbG90IA0KZ2dwbG90KGFsbF9DTUpfaW5jaWRlbnQsIGFlcyh4ID0gTWF4Lkp1bXAuSGVpZ2h0Li5jbS4sIGZpbGwgPSBTcG9ydCkpICsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC40KSArIA0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCcjQ0ZCODdDJywgJyM2NjY2NjYnLCAnIzAwMDAwMCcsICcjOEM3ODUzJykpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoJyNDRkI4N0MnLCAnIzY2NjY2NicsICcjMDAwMDAwJywgJyM4Qzc4NTMnKSkgKw0KICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBNYXhpbXVtIEp1bXAgSGVpZ2h0IChjbSkgQWNyb3NzIFNwb3J0cycsDQogICAgICAgeCA9ICdNYXhpbXVtIEp1bXAgSGVpZ2h0IChjbSknLA0KICAgICAgIHkgPSAnRGVuc2l0eScpICsNCiAgdGhlbWVfYncoKQ0KDQojYW5vdmEgdGVzdCBmb3IgZGlmZmVyZW5jZXMNCmFub3ZhX3Jlc3VsdCA8LSBhb3YoTWF4Lkp1bXAuSGVpZ2h0Li5jbS4gfiBTcG9ydCwgZGF0YSA9IGFsbF9DTUpfaW5jaWRlbnQpDQpzdW1tYXJ5KGFub3ZhX3Jlc3VsdCkNCmBgYA0KDQpgYGB7cn0NCmFsbF9DTUpfaW5jaWRlbnQgPC0gYWxsX0NNSl9pbmNpZGVudCAlPiUNCiBtdXRhdGUoVGhyZXNoMSA9IGlmZWxzZShDb25jZW50cmljLk1heGltdW0uUkZELi5OLnMuID49IDAuNSwgJ1llcycsICdObycpKQ0KDQojdGFibGUgdy8gbG93ZXIgYm9keSBpbmp1cnkgb24gbGVmdCBhbmQgd2hldGhlciB0aGUgb2JzZXJ2YXRpb24gaXMgYWJvdmUvYmVsb3cgdGhyZXNob2xkDQp0YWJsZShhbGxfQ01KX2luY2lkZW50JExCLkluanVyeSwgYWxsX0NNSl9pbmNpZGVudCRUaHJlc2gxKQ0KDQojYm94cGxvdCANCmdncGxvdChhbGxfQ01KX2luY2lkZW50LCBhZXMoeCA9IENvbmNlbnRyaWMuTWF4aW11bS5SRkQuLk4ucy4sIHkgPSBTcG9ydCkpICsNCiAgZ2VvbV9ib3hwbG90KGZpbGwgPSAnI0NGQjg3QycsIGNvbG9yID0gJ2JsYWNrJykgKyANCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgdGhlIE1heGltdW0gQ29uY2VudHJpYyBSRkQgQWNyb3NzIFNwb3J0cycsDQogICAgICAgeSA9ICdTcG9ydCcsDQogICAgICAgeCA9ICdNYXhpbXVtIENvbmNlbnRyaWMgUkZEIChOL3MpJykgKw0KICB0aGVtZV9idygpDQoNCiNkZW5zaXR5IHBsb3QgDQpnZ3Bsb3QoYWxsX0NNSl9pbmNpZGVudCwgYWVzKHggPSBDb25jZW50cmljLk1heGltdW0uUkZELi5OLnMuLCBmaWxsID0gU3BvcnQpKSArDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNCkgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygnI0NGQjg3QycsICcjNjY2NjY2JywgJyMwMDAwMDAnLCAnIzhDNzg1MycpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCcjQ0ZCODdDJywgJyM2NjY2NjYnLCAnIzAwMDAwMCcsICcjOEM3ODUzJykpICsNCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgTWF4aW11bSBDb25jZW50cmljIFJGRCAoTi9zKSBBY3Jvc3MgU3BvcnRzJywNCiAgICAgICB4ID0gJ01heGltdW0gQ29uY2VudHJpYyBSRkQgKE4vcyknLA0KICAgICAgIHkgPSAnRGVuc2l0eScpICsNCiAgdGhlbWVfYncoKQ0KDQojYW5vdmEgdGVzdCBmb3IgZGlmZmVyZW5jZXMNCmFub3ZhX3Jlc3VsdCA8LSBhb3YoQ29uY2VudHJpYy5NYXhpbXVtLlJGRC4uTi5zLiB+IFNwb3J0LCBkYXRhID0gYWxsX0NNSl9pbmNpZGVudCkNCnN1bW1hcnkoYW5vdmFfcmVzdWx0KQ0KYGBgDQoNCmBgYHtyfQ0KYWxsX0NNSl9pbmNpZGVudCA8LSBhbGxfQ01KX2luY2lkZW50ICU+JQ0KIG11dGF0ZShUaHJlc2gyID0gaWZlbHNlKEVjY2VudHJpYy5NZWFuLkJyYWtpbmcuRm9yY2UuLk4uID49IDAuNSwgJ1llcycsICdObycpKQ0KDQojdGFibGUgd2l0aCBsb3dlciBib2R5IGluanVyeSBvbiBsZWZ0IGFuZCB3aGV0aGVyIHRoZSBvYnNlcnZhdGlvbiBpcyBhYm92ZS9iZWxvdyB0aHJlc2hvbGQNCnRhYmxlKGFsbF9DTUpfaW5jaWRlbnQkTEIuSW5qdXJ5LCBhbGxfQ01KX2luY2lkZW50JFRocmVzaDIpDQoNCiNib3hwbG90IA0KZ2dwbG90KGFsbF9DTUpfaW5jaWRlbnQsIGFlcyh4ID0gRWNjZW50cmljLk1lYW4uQnJha2luZy5Gb3JjZS4uTi4sIHkgPSBTcG9ydCkpICsNCiAgZ2VvbV9ib3hwbG90KGZpbGwgPSAnI0NGQjg3QycsIGNvbG9yID0gJ2JsYWNrJykgKyANCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgdGhlIE1lYW4gRWNjZW50cmljIEJyYWtpbmcgRm9yY2UgQWNyb3NzIFNwb3J0cycsDQogICAgICAgeSA9ICdTcG9ydCcsDQogICAgICAgeCA9ICdNZWFuIEVjY2VudHJpYyBCcmFraW5nIEZvcmNlIChOKScpICsNCiAgdGhlbWVfYncoKQ0KYGBgDQoNCmBgYHtyfQ0KYWxsX0NNSl9pbmNpZGVudCA8LSBhbGxfQ01KX2luY2lkZW50ICU+JQ0KIG11dGF0ZShUaHJlc2gzID0gaWZlbHNlKE1heC5SU0kuTW9kaWZpZWQuVkFMRD49IDAuNSwgJ1llcycsICdObycpKQ0KDQojdGFibGUgd2l0aCBsb3dlciBib2R5IGluanVyeSBvbiBsZWZ0IGFuZCB3aGV0aGVyIHRoZSBvYnNlcnZhdGlvbiBpcyBhYm92ZS9iZWxvdyB0aHJlc2hvbGQNCnRhYmxlKGFsbF9DTUpfaW5jaWRlbnQkTEIuSW5qdXJ5LCBhbGxfQ01KX2luY2lkZW50JFRocmVzaDMpDQoNCiNib3hwbG90IA0KZ2dwbG90KGFsbF9DTUpfaW5jaWRlbnQsIGFlcyh4ID0gTWF4LlJTSS5Nb2RpZmllZC5WQUxELCB5ID0gU3BvcnQpKSArDQogIGdlb21fYm94cGxvdChmaWxsID0gJyNDRkI4N0MnLCBjb2xvciA9ICdibGFjaycpICsgDQogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIHRoZSBNYXhpbXVtIFJTSSBmcm9tIFZBTEQgQWNyb3NzIFNwb3J0cycsDQogICAgICAgeSA9ICdTcG9ydCcsDQogICAgICAgeCA9ICdNYXhpbXVtIFJTSSBmcm9tIFZBTEQnKSArDQogIHRoZW1lX2J3KCkNCmBgYA0KDQoyLiBIb3AgSnVtcCArIEluY2lkZW50IA0KYGBge3J9DQphbGxfaG9wanVtcF9pbmNpZGVudCA8LSBhbGxfaG9wanVtcF9pbmNpZGVudCAlPiUNCiBtdXRhdGUoVGhyZXNoID0gaWZlbHNlKE1heC5KdW1wLkhlaWdodC4uY20uID49IDAuNSwgJ1llcycsICdObycpKQ0KDQojdGFibGUgdy8gbG93ZXIgYm9keSBpbmp1cnkgb24gbGVmdCBhbmQgd2hldGhlciB0aGUgb2JzZXJ2YXRpb24gaXMgYWJvdmUvYmVsb3cgdGhyZXNob2xkDQp0YWJsZShhbGxfaG9wanVtcF9pbmNpZGVudCRMQi5Jbmp1cnksIGFsbF9ob3BqdW1wX2luY2lkZW50JFRocmVzaCkNCg0KI2JveHBsb3QgDQpnZ3Bsb3QoYWxsX2hvcGp1bXBfaW5jaWRlbnQsIGFlcyh4ID0gTWF4Lkp1bXAuSGVpZ2h0Li5jbS4sIHkgPSBTcG9ydCkpICsNCiAgZ2VvbV9ib3hwbG90KGZpbGwgPSAnI0NGQjg3QycsIGNvbG9yID0gJ2JsYWNrJykgKyANCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgdGhlIE1heGltdW0gSnVtcCBIZWlnaHQgKGNtKSBBY3Jvc3MgU3BvcnRzJywNCiAgICAgICB5ID0gJ1Nwb3J0JywNCiAgICAgICB4ID0gJ01heGltdW0gSnVtcCBIZWlnaHQgKGNtKScpICsNCiAgdGhlbWVfYncoKQ0KDQojZGVuc2l0eSBwbG90IA0KZ2dwbG90KGFsbF9ob3BqdW1wX2luY2lkZW50LCBhZXMoeCA9IE1heC5KdW1wLkhlaWdodC4uY20uLCBmaWxsID0gU3BvcnQpKSArDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNCkgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygnI0NGQjg3QycsICcjNjY2NjY2JywgJyMwMDAwMDAnLCAnIzhDNzg1MycpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCcjQ0ZCODdDJywgJyM2NjY2NjYnLCAnIzAwMDAwMCcsICcjOEM3ODUzJykpICsNCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgTWF4aW11bSBKdW1wIEhlaWdodCAoY20pIEFjcm9zcyBTcG9ydHMnLA0KICAgICAgIHggPSAnTWF4aW11bSBKdW1wIEhlaWdodCAoY20pJywNCiAgICAgICB5ID0gJ0RlbnNpdHknKSArDQogIHRoZW1lX2J3KCkNCg0KI2Fub3ZhIHRlc3QgZm9yIGRpZmZlcmVuY2VzDQphbm92YV9yZXN1bHQgPC0gYW92KE1heC5KdW1wLkhlaWdodC4uY20uIH4gU3BvcnQsIGRhdGEgPSBhbGxfaG9wanVtcF9pbmNpZGVudCkNCnN1bW1hcnkoYW5vdmFfcmVzdWx0KQ0KYGBgDQoNCmBgYHtyfQ0KYWxsX2hvcGp1bXBfaW5jaWRlbnQgPC0gYWxsX2hvcGp1bXBfaW5jaWRlbnQgJT4lDQogbXV0YXRlKFRocmVzaDEgPSBpZmVsc2UoTWVhbi5SU0kuLkZsaWdodC5Db250YWN0LlRpbWUuID49IDAuNSwgJ1llcycsICdObycpKQ0KDQojdGFibGUgdy8gbG93ZXIgYm9keSBpbmp1cnkgb24gbGVmdCBhbmQgd2hldGhlciB0aGUgb2JzZXJ2YXRpb24gaXMgYWJvdmUvYmVsb3cgdGhyZXNob2xkDQp0YWJsZShhbGxfaG9wanVtcF9pbmNpZGVudCRMQi5Jbmp1cnksIGFsbF9ob3BqdW1wX2luY2lkZW50JFRocmVzaDEpDQoNCiNib3hwbG90IA0KZ2dwbG90KGFsbF9ob3BqdW1wX2luY2lkZW50LCBhZXMoeCA9IE1lYW4uUlNJLi5GbGlnaHQuQ29udGFjdC5UaW1lLiwgeSA9IFNwb3J0KSkgKw0KICBnZW9tX2JveHBsb3QoZmlsbCA9ICcjQ0ZCODdDJywgY29sb3IgPSAnYmxhY2snKSArIA0KICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiB0aGUgQXZlcmFnZSBSU0kgRmxpZ2h0IENvbnRhY3QgVGltZSBBY3Jvc3MgU3BvcnRzJywNCiAgICAgICB5ID0gJ1Nwb3J0JywNCiAgICAgICB4ID0gJ0F2ZXJhZ2UgUlNJIEZsaWdodCBDb250YWN0IFRpbWUnKSArDQogIHRoZW1lX2J3KCkNCg0KI2RlbnNpdHkgcGxvdCANCmdncGxvdChhbGxfaG9wanVtcF9pbmNpZGVudCwgYWVzKHggPSBNZWFuLlJTSS4uRmxpZ2h0LkNvbnRhY3QuVGltZS4sIGZpbGwgPSBTcG9ydCkpICsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC40KSArIA0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCcjQ0ZCODdDJywgJ3doaXRlJywgJ2JsYWNrJywneWVsbG93JykpICsNCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgQXZlcmFnZSBSU0kgRmxpZ2h0IENvbnRhY3QgVGltZSBBY3Jvc3MgU3BvcnRzJywNCiAgICAgICB4ID0gJ0F2ZXJhZ2UgUlNJIEZsaWdodCBDb250YWN0IFRpbWUnLA0KICAgICAgIHkgPSAnRGVuc2l0eScpICsNCiAgdGhlbWVfYncoKQ0KDQojYW5vdmEgdGVzdCBmb3IgZGlmZmVyZW5jZXMNCmFub3ZhX3Jlc3VsdCA8LSBhb3YoTWVhbi5SU0kuLkZsaWdodC5Db250YWN0LlRpbWUuIH4gU3BvcnQsIGRhdGEgPSBhbGxfaG9wanVtcF9pbmNpZGVudCkNCnN1bW1hcnkoYW5vdmFfcmVzdWx0KQ0KYGBgDQoNCmBgYHtyfQ0KYWxsX2hvcGp1bXBfaW5jaWRlbnQgPC0gYWxsX2hvcGp1bXBfaW5jaWRlbnQgJT4lDQogbXV0YXRlKFRocmVzaDIgPSBpZmVsc2UoQmVzdC5Db250YWN0LlRpbWUuLm1zLiA+PSAwLjUsICdZZXMnLCAnTm8nKSkNCg0KI3RhYmxlIHcvIGxvd2VyIGJvZHkgaW5qdXJ5IG9uIGxlZnQgYW5kIHdoZXRoZXIgdGhlIG9ic2VydmF0aW9uIGlzIGFib3ZlL2JlbG93IHRocmVzaG9sZA0KdGFibGUoYWxsX2hvcGp1bXBfaW5jaWRlbnQkTEIuSW5qdXJ5LCBhbGxfaG9wanVtcF9pbmNpZGVudCRUaHJlc2gyKQ0KDQojYm94cGxvdCANCmdncGxvdChhbGxfaG9wanVtcF9pbmNpZGVudCwgYWVzKHggPSBCZXN0LkNvbnRhY3QuVGltZS4ubXMuLCB5ID0gU3BvcnQpKSArDQogIGdlb21fYm94cGxvdChmaWxsID0gJyNDRkI4N0MnLCBjb2xvciA9ICdibGFjaycpICsgDQogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIHRoZSBCZXN0IENvbnRhY3QgVGltZSAobS9zKSBBY3Jvc3MgU3BvcnRzJywNCiAgICAgICB5ID0gJ1Nwb3J0JywNCiAgICAgICB4ID0gJ0Jlc3QgQ29udGFjdCBUaW1lIChtL3MpJykgKw0KICB0aGVtZV9idygpDQoNCiNkZW5zaXR5IHBsb3QgDQpnZ3Bsb3QoYWxsX2hvcGp1bXBfaW5jaWRlbnQsIGFlcyh4ID0gQmVzdC5Db250YWN0LlRpbWUuLm1zLiwgZmlsbCA9IFNwb3J0KSkgKw0KICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjQpICsgDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoJyNDRkI4N0MnLCAnd2hpdGUnLCAnYmxhY2snLCd5ZWxsb3cnKSkgKw0KICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiB0aGUgQmVzdCBDb250YWN0IFRpbWUgKG0vcykgQWNyb3NzIFNwb3J0cycsDQogICAgICAgeCA9ICdCZXN0IENvbnRhY3QgVGltZSAobS9zKScsDQogICAgICAgeSA9ICdEZW5zaXR5JykgKw0KICB0aGVtZV9idygpDQoNCiNhbm92YSB0ZXN0IGZvciBkaWZmZXJlbmNlcw0KYW5vdmFfcmVzdWx0IDwtIGFvdihCZXN0LkNvbnRhY3QuVGltZS4ubXMuIH4gU3BvcnQsIGRhdGEgPSBhbGxfaG9wanVtcF9pbmNpZGVudCkNCnN1bW1hcnkoYW5vdmFfcmVzdWx0KQ0KYGBgDQoNCjMuIElzb21ldHJpYyBNaWQgVGhpZ2ggUHVsbCAoSU1UUCkgKyBJbmNpZGVudCANCmBgYHtyfQ0KI2NvdWxkIHVzZSB0aGlzIG9yIFBlYWsuVmVydGljYWwuRm9yY2UuLk4uIG9yIE5ldC5QZWFrLlZlcnRpY2FsLkZvcmNlLi5OLnMuDQphbGxfSU1UUF9pbmNpZGVudCA8LSBhbGxfSU1UUF9pbmNpZGVudCAlPiUNCiBtdXRhdGUoVGhyZXNoID0gaWZlbHNlKFBlYWsuVmVydGljYWwuRm9yY2UuLi5CTS4uTi5rZy4gPj0gMC41LCAnWWVzJywgJ05vJykpDQoNCiN0YWJsZSB3LyBsb3dlciBib2R5IGluanVyeSBvbiBsZWZ0IGFuZCB3aGV0aGVyIHRoZSBvYnNlcnZhdGlvbiBpcyBhYm92ZS9iZWxvdyB0aHJlc2hvbGQNCnRhYmxlKGFsbF9JTVRQX2luY2lkZW50JExCLkluanVyeSwgYWxsX0lNVFBfaW5jaWRlbnQkVGhyZXNoKQ0KDQojYm94cGxvdCANCmdncGxvdChhbGxfSU1UUF9pbmNpZGVudCwgYWVzKHggPSBQZWFrLlZlcnRpY2FsLkZvcmNlLi4uQk0uLk4ua2cuLCB5ID0gU3BvcnQpKSArDQogIGdlb21fYm94cGxvdChmaWxsID0gJyNDRkI4N0MnLCBjb2xvciA9ICdibGFjaycpICsgDQogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIHRoZSBQZWFrIFZlcnRpY2FsIEZvcmNlIEFjcm9zcyBTcG9ydHMnLA0KICAgICAgIHkgPSAnU3BvcnQnLA0KICAgICAgIHggPSAnUGVhayBWZXJ0aWNhbCBGb3JjZSAoQk0gTi9rZyknKSArDQogIHRoZW1lX2J3KCkNCg0KI2RlbnNpdHkgcGxvdCANCmdncGxvdChhbGxfSU1UUF9pbmNpZGVudCwgYWVzKHggPSBQZWFrLlZlcnRpY2FsLkZvcmNlLi4uQk0uLk4ua2cuLCBmaWxsID0gU3BvcnQpKSArDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNCkgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygnI0NGQjg3QycsICd3aGl0ZScsICdibGFjaycsJ3llbGxvdycpKSArDQogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIHRoZSBQZWFrIFZlcnRpY2FsIEZvcmNlIEFjcm9zcyBTcG9ydHMnLA0KICAgICAgIHggPSAnUGVhayBWZXJ0aWNhbCBGb3JjZSAoQk0gTi9rZyknLA0KICAgICAgIHkgPSAnRGVuc2l0eScpICsNCiAgdGhlbWVfYncoKQ0KDQojYW5vdmEgdGVzdCBmb3IgZGlmZmVyZW5jZXMNCmFub3ZhX3Jlc3VsdCA8LSBhb3YoUGVhay5WZXJ0aWNhbC5Gb3JjZS4uLkJNLi5OLmtnLiB+IFNwb3J0LCBkYXRhID0gYWxsX0lNVFBfaW5jaWRlbnQpDQpzdW1tYXJ5KGFub3ZhX3Jlc3VsdCkNCmBgYA0KDQpgYGB7cn0NCmFsbF9JTVRQX2luY2lkZW50IDwtIGFsbF9JTVRQX2luY2lkZW50ICU+JQ0KIG11dGF0ZShUaHJlc2gxID0gaWZlbHNlKFJGRC4uLjIwMG1zLi5OLnMuID49IDAuNSwgJ1llcycsICdObycpKQ0KDQojdGFibGUgdy8gbG93ZXIgYm9keSBpbmp1cnkgb24gbGVmdCBhbmQgd2hldGhlciB0aGUgb2JzZXJ2YXRpb24gaXMgYWJvdmUvYmVsb3cgdGhyZXNob2xkDQp0YWJsZShhbGxfSU1UUF9pbmNpZGVudCRMQi5Jbmp1cnksIGFsbF9JTVRQX2luY2lkZW50JFRocmVzaDEpDQoNCiNib3hwbG90IA0KZ2dwbG90KGFsbF9JTVRQX2luY2lkZW50LCBhZXMoeCA9IFJGRC4uLjIwMG1zLi5OLnMuLCB5ID0gU3BvcnQpKSArDQogIGdlb21fYm94cGxvdChmaWxsID0gJyNDRkI4N0MnLCBjb2xvciA9ICdibGFjaycpICsgDQogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIHRoZSBSYXRlIG9mIEZvcmNlIERldmVsb3BtZW50IGF0IDIwMG1zIEFjcm9zcyBTcG9ydHMnLA0KICAgICAgIHkgPSAnU3BvcnQnLA0KICAgICAgIHggPSAnUmF0ZSBvZiBGb3JjZSBEZXZlbG9wbWVudCBhdCAyMDBtcyAoTi9zKScpICsNCiAgdGhlbWVfYncoKQ0KDQojZGVuc2l0eSBwbG90IA0KZ2dwbG90KGFsbF9JTVRQX2luY2lkZW50LCBhZXMoeCA9IFJGRC4uLjIwMG1zLi5OLnMuLCBmaWxsID0gU3BvcnQpKSArDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNCkgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygnI0NGQjg3QycsICd3aGl0ZScsICdibGFjaycsJ3llbGxvdycpKSArDQogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIHRoZSBSYXRlIG9mIEZvcmNlIERldmVsb3BtZW50IGF0IDIwMG1zIEFjcm9zcyBTcG9ydHMnLA0KICAgICAgIHggPSAnUmF0ZSBvZiBGb3JjZSBEZXZlbG9wbWVudCBhdCAyMDBtcyAoTi9zKScsDQogICAgICAgeSA9ICdEZW5zaXR5JykgKw0KICB0aGVtZV9idygpDQoNCiNhbm92YSB0ZXN0IGZvciBkaWZmZXJlbmNlcw0KYW5vdmFfcmVzdWx0IDwtIGFvdihSRkQuLi4yMDBtcy4uTi5zLiB+IFNwb3J0LCBkYXRhID0gYWxsX0lNVFBfaW5jaWRlbnQpDQpzdW1tYXJ5KGFub3ZhX3Jlc3VsdCkNCmBgYA0KDQpgYGB7cn0NCmFsbF9JTVRQX2luY2lkZW50IDwtIGFsbF9JTVRQX2luY2lkZW50ICU+JQ0KIG11dGF0ZShUaHJlc2gyID0gaWZlbHNlKEZvcmNlLmF0LjIwMG1zLi4uQk0uLk4ua2cuID49IDAuNSwgJ1llcycsICdObycpKQ0KDQojdGFibGUgdy8gbG93ZXIgYm9keSBpbmp1cnkgb24gbGVmdCBhbmQgd2hldGhlciB0aGUgb2JzZXJ2YXRpb24gaXMgYWJvdmUvYmVsb3cgdGhyZXNob2xkDQp0YWJsZShhbGxfSU1UUF9pbmNpZGVudCRMQi5Jbmp1cnksIGFsbF9JTVRQX2luY2lkZW50JFRocmVzaDIpDQoNCiNib3hwbG90IA0KZ2dwbG90KGFsbF9JTVRQX2luY2lkZW50LCBhZXMoeCA9IEZvcmNlLmF0LjIwMG1zLi4uQk0uLk4ua2cuLCB5ID0gU3BvcnQpKSArDQogIGdlb21fYm94cGxvdChmaWxsID0gJyNDRkI4N0MnLCBjb2xvciA9ICdibGFjaycpICsgDQogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIHRoZSBGb3JjZSBhdCAyMDBtcyBBY3Jvc3MgU3BvcnRzJywNCiAgICAgICB5ID0gJ1Nwb3J0JywNCiAgICAgICB4ID0gJ0ZvcmNlIGF0IDIwMG1zIEJNIChOL2tnKScpICsNCiAgdGhlbWVfYncoKQ0KDQojZGVuc2l0eSBwbG90IA0KZ2dwbG90KGFsbF9JTVRQX2luY2lkZW50LCBhZXMoeCA9IEZvcmNlLmF0LjIwMG1zLi4uQk0uLk4ua2cuLCBmaWxsID0gU3BvcnQpKSArDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNCkgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygnI0NGQjg3QycsICd3aGl0ZScsICdibGFjaycsJ3llbGxvdycpKSArDQogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIHRoZSBGb3JjZSBhdCAyMDBtcyBBY3Jvc3MgU3BvcnRzJywNCiAgICAgICB4ID0gJ0ZvcmNlIGF0IDIwMG1zIEJNIChOL2tnKScsDQogICAgICAgeSA9ICdEZW5zaXR5JykgKw0KICB0aGVtZV9idygpDQoNCiNhbm92YSB0ZXN0IGZvciBkaWZmZXJlbmNlcw0KYW5vdmFfcmVzdWx0IDwtIGFvdihGb3JjZS5hdC4yMDBtcy4uLkJNLi5OLmtnLiB+IFNwb3J0LCBkYXRhID0gYWxsX0lNVFBfaW5jaWRlbnQpDQpzdW1tYXJ5KGFub3ZhX3Jlc3VsdCkNCmBgYA0KDQo0LiBTaW5nbGUgTGVnIEp1bXAgKyBJbmNpZGVudCANCmBgYHtyfQ0KYWxsX1NMSl9pbmNpZGVudCA8LSBhbGxfU0xKX2luY2lkZW50ICU+JQ0KIG11dGF0ZShUaHJlc2ggPSBpZmVsc2UoTWF4Lkp1bXAuSGVpZ2h0Li5jbS4gPj0gMC41LCAnWWVzJywgJ05vJykpDQoNCiN0YWJsZSB3LyBsb3dlciBib2R5IGluanVyeSBvbiBsZWZ0IGFuZCB3aGV0aGVyIHRoZSBvYnNlcnZhdGlvbiBpcyBhYm92ZS9iZWxvdyB0aHJlc2hvbGQNCnRhYmxlKGFsbF9TTEpfaW5jaWRlbnQkTEIuSW5qdXJ5LCBhbGxfU0xKX2luY2lkZW50JFRocmVzaCkNCg0KI2JveHBsb3QgDQpnZ3Bsb3QoYWxsX1NMSl9pbmNpZGVudCwgYWVzKHggPSBNYXguSnVtcC5IZWlnaHQuLmNtLiwgeSA9IFNwb3J0KSkgKw0KICBnZW9tX2JveHBsb3QoZmlsbCA9ICcjQ0ZCODdDJywgY29sb3IgPSAnYmxhY2snKSArIA0KICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiB0aGUgTWF4aW11bSBKdW1wIEhlaWdodCBBY3Jvc3MgU3BvcnRzJywNCiAgICAgICB5ID0gJ1Nwb3J0JywNCiAgICAgICB4ID0gJ01heGltdW0gSnVtcCBIZWlnaHQgKGNtKScpICsNCiAgdGhlbWVfYncoKQ0KDQojZGVuc2l0eSBwbG90IA0KZ2dwbG90KGFsbF9TTEpfaW5jaWRlbnQsIGFlcyh4ID0gTWF4Lkp1bXAuSGVpZ2h0Li5jbS4sIGZpbGwgPSBTcG9ydCkpICsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC40KSArIA0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCcjQ0ZCODdDJywgJ3doaXRlJywgJ2JsYWNrJywneWVsbG93JykpICsNCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgdGhlIE1heGltdW0gSnVtcCBIZWlnaHQgQWNyb3NzIFNwb3J0cycsDQogICAgICAgeCA9ICdNYXhpbXVtIEp1bXAgSGVpZ2h0IChjbSknLA0KICAgICAgIHkgPSAnRGVuc2l0eScpICsNCiAgdGhlbWVfYncoKQ0KDQojYW5vdmEgdGVzdCBmb3IgZGlmZmVyZW5jZXMNCmFub3ZhX3Jlc3VsdCA8LSBhb3YoTWF4Lkp1bXAuSGVpZ2h0Li5jbS4gfiBTcG9ydCwgZGF0YSA9IGFsbF9TTEpfaW5jaWRlbnQpDQpzdW1tYXJ5KGFub3ZhX3Jlc3VsdCkNCmBgYA0KDQpgYGB7cn0NCiNDSE9PU0UgVE8gS0VFUCBUSElTIE9ORSBPUiBPTkUgRElSRUNUTFkgQUJPVkUgDQphbGxfU0xKX2luY2lkZW50IDwtIGFsbF9TTEpfaW5jaWRlbnQgJT4lDQogbXV0YXRlKFRocmVzaDEgPSBpZmVsc2UoSnVtcC5IZWlnaHQuLkZsaWdodC5UaW1lLi4uY20uID49IDAuNSwgJ1llcycsICdObycpKQ0KDQojdGFibGUgdy8gbG93ZXIgYm9keSBpbmp1cnkgb24gbGVmdCBhbmQgd2hldGhlciB0aGUgb2JzZXJ2YXRpb24gaXMgYWJvdmUvYmVsb3cgdGhyZXNob2xkDQp0YWJsZShhbGxfU0xKX2luY2lkZW50JExCLkluanVyeSwgYWxsX1NMSl9pbmNpZGVudCRUaHJlc2gxKQ0KDQojYm94cGxvdCANCmdncGxvdChhbGxfU0xKX2luY2lkZW50LCBhZXMoeCA9IEp1bXAuSGVpZ2h0Li5GbGlnaHQuVGltZS4uLmNtLiwgeSA9IFNwb3J0KSkgKw0KICBnZW9tX2JveHBsb3QoZmlsbCA9ICcjQ0ZCODdDJywgY29sb3IgPSAnYmxhY2snKSArIA0KICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiB0aGUgSnVtcCBIZWlnaHQgRmxpZ2h0IFRpbWUgQWNyb3NzIFNwb3J0cycsDQogICAgICAgeSA9ICdTcG9ydCcsDQogICAgICAgeCA9ICdKdW1wIEhlaWdodCBGbGlnaHQgVGltZSAoY20pJykgKw0KICB0aGVtZV9idygpDQoNCiNkZW5zaXR5IHBsb3QgDQpnZ3Bsb3QoYWxsX1NMSl9pbmNpZGVudCwgYWVzKHggPSBKdW1wLkhlaWdodC4uRmxpZ2h0LlRpbWUuLi5jbS4sIGZpbGwgPSBTcG9ydCkpICsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC40KSArIA0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCcjQ0ZCODdDJywgJ3doaXRlJywgJ2JsYWNrJywneWVsbG93JykpICsNCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgdGhlIEp1bXAgSGVpZ2h0IEZsaWdodCBUaW1lICBBY3Jvc3MgU3BvcnRzJywNCiAgICAgICB4ID0gJ0p1bXAgSGVpZ2h0IEZsaWdodCBUaW1lIChjbSknLA0KICAgICAgIHkgPSAnRGVuc2l0eScpICsNCiAgdGhlbWVfYncoKQ0KDQojYW5vdmEgdGVzdCBmb3IgZGlmZmVyZW5jZXMNCmFub3ZhX3Jlc3VsdCA8LSBhb3YoSnVtcC5IZWlnaHQuLkZsaWdodC5UaW1lLi4uY20uIH4gU3BvcnQsIGRhdGEgPSBhbGxfU0xKX2luY2lkZW50KQ0Kc3VtbWFyeShhbm92YV9yZXN1bHQpDQpgYGANCg0KYGBge3J9DQphbGxfU0xKX2luY2lkZW50IDwtIGFsbF9TTEpfaW5jaWRlbnQgJT4lDQogbXV0YXRlKFRocmVzaDIgPSBpZmVsc2UoTGFuZGluZy5SRkQuLk4ucy4gPj0gMC41LCAnWWVzJywgJ05vJykpDQoNCiN0YWJsZSB3LyBsb3dlciBib2R5IGluanVyeSBvbiBsZWZ0IGFuZCB3aGV0aGVyIHRoZSBvYnNlcnZhdGlvbiBpcyBhYm92ZS9iZWxvdyB0aHJlc2hvbGQNCnRhYmxlKGFsbF9TTEpfaW5jaWRlbnQkTEIuSW5qdXJ5LCBhbGxfU0xKX2luY2lkZW50JFRocmVzaDIpDQoNCiNib3hwbG90IA0KZ2dwbG90KGFsbF9TTEpfaW5jaWRlbnQsIGFlcyh4ID0gTGFuZGluZy5SRkQuLk4ucy4sIHkgPSBTcG9ydCkpICsNCiAgZ2VvbV9ib3hwbG90KGZpbGwgPSAnI0NGQjg3QycsIGNvbG9yID0gJ2JsYWNrJykgKyANCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgdGhlIExhbmRpbmcgUmF0ZSBvZiBGb3JjZSBEZXZlbG9wbWVudCBBY3Jvc3MgU3BvcnRzJywNCiAgICAgICB5ID0gJ1Nwb3J0JywNCiAgICAgICB4PSAnTGFuZGluZyBSYXRlIG9mIEZvcmNlIERldmVsb3BtZW50IChOL3MpJykgKw0KICB0aGVtZV9idygpDQoNCiNkZW5zaXR5IHBsb3QgDQpnZ3Bsb3QoYWxsX1NMSl9pbmNpZGVudCwgYWVzKHggPSBMYW5kaW5nLlJGRC4uTi5zLiwgZmlsbCA9IFNwb3J0KSkgKw0KICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjQpICsgDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoJyNDRkI4N0MnLCAnd2hpdGUnLCAnYmxhY2snLCd5ZWxsb3cnKSkgKw0KICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiB0aGUgTGFuZGluZyBSYXRlIG9mIEZvcmNlIERldmVsb3BtZW50IEFjcm9zcyBTcG9ydHMnLA0KICAgICAgIHggPSAnTGFuZGluZyBSYXRlIG9mIEZvcmNlIERldmVsb3BtZW50IChOL3MpJywNCiAgICAgICB5ID0gJ0RlbnNpdHknKSArDQogIHRoZW1lX2J3KCkNCg0KI2Fub3ZhIHRlc3QgZm9yIGRpZmZlcmVuY2VzDQphbm92YV9yZXN1bHQgPC0gYW92KExhbmRpbmcuUkZELi5OLnMuIH4gU3BvcnQsIGRhdGEgPSBhbGxfU0xKX2luY2lkZW50KQ0Kc3VtbWFyeShhbm92YV9yZXN1bHQpDQpgYGANCg0KYGBge3J9DQphbGxfU0xKX2luY2lkZW50IDwtIGFsbF9TTEpfaW5jaWRlbnQgJT4lDQogbXV0YXRlKFRocmVzaDIgPSBpZmVsc2UoTWF4LkNvbmNlbnRyaWMuUGVhay5Gb3JjZS4uTi4gPj0gMC41LCAnWWVzJywgJ05vJykpDQoNCiN0YWJsZSB3LyBsb3dlciBib2R5IGluanVyeSBvbiBsZWZ0IGFuZCB3aGV0aGVyIHRoZSBvYnNlcnZhdGlvbiBpcyBhYm92ZS9iZWxvdyB0aHJlc2hvbGQNCnRhYmxlKGFsbF9TTEpfaW5jaWRlbnQkTEIuSW5qdXJ5LCBhbGxfU0xKX2luY2lkZW50JFRocmVzaDIpDQoNCiNib3hwbG90IA0KZ2dwbG90KGFsbF9TTEpfaW5jaWRlbnQsIGFlcyh4ID0gTWF4LkNvbmNlbnRyaWMuUGVhay5Gb3JjZS4uTi4sIHkgPSBTcG9ydCkpICsNCiAgZ2VvbV9ib3hwbG90KGZpbGwgPSAnI0NGQjg3QycsIGNvbG9yID0gJ2JsYWNrJykgKyANCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgdGhlIE1heGltdW0gQ29uY2VudHJpYyBQZWFrIEZvcmNlIEFjcm9zcyBTcG9ydHMnLA0KICAgICAgIHkgPSAnU3BvcnQnLA0KICAgICAgIHg9ICdNYXhpbXVtIENvbmNlbnRyaWMgUGVhayBGb3JjZSAoTiknKSArDQogIHRoZW1lX2J3KCkNCg0KI2RlbnNpdHkgcGxvdCANCmdncGxvdChhbGxfU0xKX2luY2lkZW50LCBhZXMoeCA9IE1heC5Db25jZW50cmljLlBlYWsuRm9yY2UuLk4uLCBmaWxsID0gU3BvcnQpKSArDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNCkgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygnI0NGQjg3QycsICd3aGl0ZScsICdibGFjaycsJ3llbGxvdycpKSArDQogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIHRoZSBNYXhpbXVtIENvbmNlbnRyaWMgUGVhayBGb3JjZSBBY3Jvc3MgU3BvcnRzJywNCiAgICAgICB4ID0gJ01heGltdW0gQ29uY2VudHJpYyBQZWFrIEZvcmNlIChOKScsDQogICAgICAgeSA9ICdEZW5zaXR5JykgKw0KICB0aGVtZV9idygpDQoNCiNhbm92YSB0ZXN0IGZvciBkaWZmZXJlbmNlcw0KYW5vdmFfcmVzdWx0IDwtIGFvdihNYXguQ29uY2VudHJpYy5QZWFrLkZvcmNlLi5OLiB+IFNwb3J0LCBkYXRhID0gYWxsX1NMSl9pbmNpZGVudCkNCnN1bW1hcnkoYW5vdmFfcmVzdWx0KQ0KYGBgDQoNCmBgYHtyfQ0KYWxsX1NMSl9pbmNpZGVudCA8LSBhbGxfU0xKX2luY2lkZW50ICU+JQ0KIG11dGF0ZShUaHJlc2gzID0gaWZlbHNlKENvbmNlbnRyaWMuSW1wdWxzZS4uTnMuID49IDAuNSwgJ1llcycsICdObycpKQ0KDQojdGFibGUgdy8gbG93ZXIgYm9keSBpbmp1cnkgb24gbGVmdCBhbmQgd2hldGhlciB0aGUgb2JzZXJ2YXRpb24gaXMgYWJvdmUvYmVsb3cgdGhyZXNob2xkDQp0YWJsZShhbGxfU0xKX2luY2lkZW50JExCLkluanVyeSwgYWxsX1NMSl9pbmNpZGVudCRUaHJlc2gzKQ0KDQojYm94cGxvdCANCmdncGxvdChhbGxfU0xKX2luY2lkZW50LCBhZXMoeCA9IE1heC5Db25jZW50cmljLlBlYWsuRm9yY2UuLk4uLCB5ID0gU3BvcnQpKSArDQogIGdlb21fYm94cGxvdChmaWxsID0gJyNDRkI4N0MnLCBjb2xvciA9ICdibGFjaycpICsgDQogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIHRoZSBDb25jZW50cmljIEltcHVsc2UgQWNyb3NzIFNwb3J0cycsDQogICAgICAgeSA9ICdTcG9ydCcsDQogICAgICAgeD0gJ0NvbmNlbnRyaWMgSW1wdWxzZSAoTi9zKScpICsNCiAgdGhlbWVfYncoKQ0KDQojZGVuc2l0eSBwbG90IA0KZ2dwbG90KGFsbF9TTEpfaW5jaWRlbnQsIGFlcyh4ID0gQ29uY2VudHJpYy5JbXB1bHNlLi5Ocy4sIGZpbGwgPSBTcG9ydCkpICsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC40KSArIA0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCcjQ0ZCODdDJywgJ3doaXRlJywgJ2JsYWNrJywneWVsbG93JykpICsNCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgdGhlIENvbmNlbnRyaWMgSW1wdWxzZSAgQWNyb3NzIFNwb3J0cycsDQogICAgICAgeCA9ICdDb25jZW50cmljIEltcHVsc2UgKE4vcyknLA0KICAgICAgIHkgPSAnRGVuc2l0eScpICsNCiAgdGhlbWVfYncoKQ0KDQojYW5vdmEgdGVzdCBmb3IgZGlmZmVyZW5jZXMNCmFub3ZhX3Jlc3VsdCA8LSBhb3YoQ29uY2VudHJpYy5JbXB1bHNlLi5Ocy4gfiBTcG9ydCwgZGF0YSA9IGFsbF9TTEpfaW5jaWRlbnQpDQpzdW1tYXJ5KGFub3ZhX3Jlc3VsdCkNCmBgYA0KDQojIyBSZWNyZWF0aW5nIE5vcm1hdGl2ZSBEYXRhDQojIyMgQ01KIERhdGENCg0KYGBge3J9DQojY3JlYXRpbmcgYSBkYXRhc2V0IGNvbnRhaW5pbmcgYWxsIGluZm9ybWF0aW9uIGZvciBDTUoNCmNtaiA8LSByYmluZChiLCBzLCBsLCB2KSAlPiUNCiAgbXV0YXRlKFNwb3J0LjIgPSBpZmVsc2UoU3BvcnQgPT0gJ0Jhc2tldGJhbGwnIHwgU3BvcnQgPT0gJ1ZvbGxleWJhbGwnLCAnQ291cnQnLCAnRmllbGQnKSkgJT4lDQogIGZpbHRlcihKdW1wLkhlaWdodC4uSW1wLk1vbS4uLmNtLiA8IDEwMCkNCg0KI3N1bW1hcml6ZXMgaW1wb3J0YW50IG1ldHJpY3MNCmNtaiAlPiUNCiAgZ3JvdXBfYnkoU3BvcnQpICU+JQ0KICBzdW1tYXJpemUoYEF2ZXJhZ2UgRGVwdGhgID0gbWVhbihDb3VudGVybW92ZW1lbnQuRGVwdGguLmNtLiksDQogICAgICAgICAgICBgUGVhayBQb3dlciB3LyBCV2AgPSBtZWFuKFBlYWsuUG93ZXIuLi5CTS4uVy5rZy4pLA0KICAgICAgICAgICAgYFBlYWsgUG93ZXJgID0gbWVhbihQZWFrLlBvd2VyLi5XLiksDQogICAgICAgICAgICBgRWNjL0NvbmMgRm9yY2UgUmF0aW9gID0gbWVhbihFY2NlbnRyaWMuQ29uY2VudHJpYy5NZWFuLkZvcmNlLlJhdGlvKSwNCiAgICAgICAgICAgIGBFY2MgQnJha2luZyBGb3JjZWAgPSBtZWFuKEVjY2VudHJpYy5NZWFuLkJyYWtpbmcuRm9yY2UuLk4uKSwNCiAgICAgICAgICAgIGBDb25jIFRpbWUgdG8gUGVha2AgPSBtZWFuKENvbmNlbnRyaWMuVGltZS50by5QZWFrLkZvcmNlLi5zLiksDQogICAgICAgICAgICBgRFNJYCA9IG1lYW4oRFNJKSkNCmBgYA0KDQpUaGlzIGNvZGUgd2l0aCBkaWZmZXJlbnQgdmFyaWFibGVzIGFuZC9vciBzcG9ydHMgc3dpdGNoZWQgb3V0IHdhcyB1c2VkIG11bHRpcGxlIHRpbWVzLiANCg0KYGBge3J9DQojY3JlYXRlcyBhIGRlbnNpdHkgcGxvdCBmb3IganVtcCBoZWlnaHQgYWNyb3NzIHNwb3J0cw0KZ2dwbG90KGNtaiwgYWVzKHggPSBKdW1wLkhlaWdodC4uSW1wLk1vbS4uLmNtLiwgY29sb3IgPSBTcG9ydCwgZmlsbCA9IFNwb3J0KSkgKyANCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC40KSArIA0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCcjQ0ZCODdDJywgJyM2NjY2NjYnLCAnIzAwMDAwMCcsICcjOEM3ODUzJykpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoJyNDRkI4N0MnLCAnIzY2NjY2NicsICcjMDAwMDAwJywgJyM4Qzc4NTMnKSkgKw0KICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBKdW1wIEhlaWdodCBBY3Jvc3MgU3BvcnRzJywNCiAgICAgICB4ID0gJ0p1bXAgSGVpZ2h0IChjbSknLA0KICAgICAgIHkgPSAnRGVuc2l0eScpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcShmcm9tID0gMCwgdG8gPSAxMDAsIGJ5ID0gNSkpICsNCiAgdGhlbWVfYncoKQ0KYGBgDQoNCmBgYHtyfQ0KI2NyZWF0ZXMgYSBkZW5zaXR5IHBsb3QgZm9yIGp1bXAgaGVpZ2h0IGFjcm9zcyBzcG9ydHMNCmdncGxvdChjbWosIGFlcyh4ID0gSnVtcC5IZWlnaHQuLkltcC5Nb20uLi5jbS4sIGNvbG9yID0gU3BvcnQuMiwgZmlsbCA9IFNwb3J0LjIpKSArIA0KICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjUpICsgDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoJyNDRkI4N0MnLCAnIzAwMDAwMCcpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCcjQ0ZCODdDJywgJyMwMDAwMDAnKSkgKw0KICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBKdW1wIEhlaWdodCBBY3Jvc3MgU3BvcnRzJywNCiAgICAgICB4ID0gJ0p1bXAgSGVpZ2h0IChjbSknLA0KICAgICAgIHkgPSAnRGVuc2l0eScsDQogICAgICAgZmlsbCA9ICdTcG9ydCBUeXBlJywNCiAgICAgICBjb2xvciA9ICdTcG9ydCBUeXBlJykgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKGZyb20gPSAwLCB0byA9IDEwMCwgYnkgPSA1KSkgKw0KICB0aGVtZV9idygpDQpgYGANCg0KYGBge3J9DQojcmVhZHMgaW4gdGhlIGltYWdlIG9mIHRoZSBub3JtYXRpdmUgZGF0YSBhbmQgbm9ybWFsaXplcyB0aGUgc2l6ZQ0KaW1nIDwtIGltYWdlX3JlYWQoImpoX3dseC5wbmciKQ0KaW1nX2dyb2IgPC0gcmFzdGVyR3JvYihpbWcsIGludGVycG9sYXRlID0gVFJVRSkNCmltZ19wbG90IDwtIGdnZHJhdygpICsgZHJhd19ncm9iKGltZ19ncm9iLCB4ID0gMCwgeSA9IDAsIHdpZHRoID0gMSwgaGVpZ2h0ID0gMSkNCg0KI2NyZWF0ZXMgYSBwbG90IG9mIHRoZSBDVSBkYXRhIG5hbWVkICJwIg0KcCA8LSBnZ3Bsb3QobCwgYWVzKHggPSBKdW1wLkhlaWdodC4uSW1wLk1vbS4uLmNtLikpICsgDQogIGdlb21fZGVuc2l0eShmaWxsID0gJyNDRkI4N0MnKSArDQogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIEp1bXAgSGVpZ2h0JywNCiAgICAgICB4ID0gJ0p1bXAgSGVpZ2h0IChjbSknLA0KICAgICAgIHkgPSAnRGVuc2l0eScsDQogICAgICAgY2FwdGlvbiA9ICdDVSBXb21lbnMgTGFjcm9zc2UnKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IG1lZGlhbihsJEp1bXAuSGVpZ2h0Li5JbXAuTW9tLi4uY20uKSwgbGluZXR5cGUgPSAnc29saWQnKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMocXVhbnRpbGUobCRKdW1wLkhlaWdodC4uSW1wLk1vbS4uLmNtLiwgcHJvYnMgPSBjKDAuMDEsIDAuMjUsIDAuNzUsIDAuOTkpKSksIGxpbmV0eXBlID0gJ2Rhc2hlZCcpICsgDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoZnJvbSA9IDAsIHRvID0gMTAwLCBieSA9IDUpKSArIA0KICB0aGVtZV9idygpDQoNCiNjb21iaW5lcyBib3RoIHRoZSBDVSBkYXRhIGRlbnNpdHkgcGxvdCBhbmQgcHV0cyBub3JtYXRpdmUgaW1hZ2Ugb24gdGhlIHJpZ2h0DQpjb21iaW5lZCA8LSBwbG90X2dyaWQocCwgaW1nX3Bsb3QsIA0KICAgICAgICAgICAgICAgICAgICAgIHJlbF93aWR0aHMgPSBjKDEuNSwgMSksIA0KICAgICAgICAgICAgICAgICAgICAgIG5yb3cgPSAxLCAgICAgICAjIDwtIGhvcml6b250YWwgbGF5b3V0DQogICAgICAgICAgICAgICAgICAgICAgYWxpZ24gPSAiaCIpICAgICMgPC0gYWxpZ24gaG9yaXpvbnRhbGx5IA0KDQojcHJpbnRzIGZpbmFsIGdyYXBoaWMNCmNvbWJpbmVkDQpgYGANCg0KYGBge3J9DQojY2FsY3VsYXRlcyB0aGUgMjV0aCwgNTB0aCwgYW5kIDc1dGggcGVyY2VudGlsZSBvZiBDVSBkYXRhDQpxdWFudGlsZShsJEp1bXAuSGVpZ2h0Li5JbXAuTW9tLi4uY20uLCBwcm9icyA9IGMoMC4yNSwgMC41LCAwLjc1KSkNCmBgYA0KDQpgYGB7cn0NCiNwZXJmb3JtcyBhIFdlbGNoJ3MgVC10ZXN0IGZvciBkaWZmZXJlbmNlIG9mIG1lYW5zIG9mIGRpZmZlcmVudCB2YXJpYWJsZXMgYmV0d2VlbiB0aGUgY291cnQgYW5kIGZpZWxkIHNwb3J0cw0KdC50ZXN0KFBlYWsuTmV0LlRha2VvZmYuRm9yY2UuLi5CTS4uTi5rZy4gfiBTcG9ydC4yLCBkYXRhID0gY21qKQ0KdC50ZXN0KExhbmRpbmcuTmV0LlBlYWsuRm9yY2UuLi5CTS4uTi5rZy4gfiBTcG9ydC4yLCBkYXRhID0gY21qKQ0KdC50ZXN0KEZvcmNlLmF0LlBlYWsuUG93ZXIuLk4uIH4gU3BvcnQuMiwgZGF0YSA9IGNtaikNCnQudGVzdChSU0kuTW9kaWZpZWQuLm0ucy4gfiBTcG9ydC4yLCBkYXRhID0gY21qKQ0KdC50ZXN0KERTSSB+IFNwb3J0LjIsIGRhdGEgPSBjbWopDQpgYGANCg0KTW9zdCBkaWZmZXJlbmNlcyBhcmUgdmVyeSBzaWduaWZpY2FudCBiZXR3ZWVuIGNvdXJ0IGFuZCBmaWVsZCBzcG9ydHMuIA0KDQpgYGB7cn0NCiN1c2VzIGEgd2VsY2ggdHdvIHNhbXBsZSB0LXRlc3QgdG8gdGVzdCBmb3IgZGlmZmVyZW5jZXMgYmV0d2VlbiBzcG9ydHM6IGZpbHRlcnMgZm9yIGp1c3QgdHdvIHRvIHNlZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIGFsbCBzcG9ydHMNCnQudGVzdChGb3JjZS5hdC5QZWFrLlBvd2VyLi5OLiB+IFNwb3J0LCBkYXRhID0gY21qICU+JSBmaWx0ZXIoU3BvcnQgJWluJSBjKCdTb2NjZXInLCAnTGFjcm9zc2UnKSkpDQpgYGANCg0KIyMjIEhKIERhdGENCg0KYGBge3J9DQojY3JlYXRpbmcgYSBkYXRhc2V0IGNvbnRhaW5pbmcgYWxsIGluZm9ybWF0aW9uIGZvciBISg0KaGogPC0gcmJpbmQoSEpfQiwgSEpfUywgSEpfTCwgSEpfVikgJT4lDQogIG11dGF0ZShTcG9ydC4yID0gaWZlbHNlKFNwb3J0ID09ICdCYXNrZXRiYWxsJyB8IFNwb3J0ID09ICdWb2xsZXliYWxsJywgJ0NvdXJ0JywgJ0ZpZWxkJykpDQpgYGANCg0KYGBge3J9DQojY3JlYXRlcyBhIGRlbnNpdHkgcGxvdCBmb3IgbWVhbiBjb250YWN0IHRpbWUgYWNyb3NzIHNwb3J0cw0KZ2dwbG90KGhqLCBhZXMoeCA9IE1lYW4uQ29udGFjdC5UaW1lLi5tcy4sIGNvbG9yID0gU3BvcnQsIGZpbGwgPSBTcG9ydCkpICsgDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNCkgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygnI0NGQjg3QycsICcjNjY2NjY2JywgJyMwMDAwMDAnLCAnIzhDNzg1MycpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCcjQ0ZCODdDJywgJyM2NjY2NjYnLCAnIzAwMDAwMCcsICcjOEM3ODUzJykpICsNCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgTWVhbiBDb250YWN0IFRpbWUgQWNyb3NzIFNwb3J0cycsDQogICAgICAgeCA9ICdNZWFuIENvbnRhY3QgVGltZSAocyknLA0KICAgICAgIHkgPSAnRGVuc2l0eScpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcShmcm9tID0gMCwgdG8gPSA3LCBieSA9IDAuMDQpKSArIA0KICB0aGVtZV9idygpDQpgYGANCg0KYGBge3J9DQojY3JlYXRlcyBhIGRlbnNpdHkgcGxvdCBmb3IgbWVhbiBjb250YWN0IHRpbWUgYWNyb3NzIHNwb3J0cw0KZ2dwbG90KGhqLCBhZXMoeCA9IE1lYW4uQ29udGFjdC5UaW1lLi5tcy4sIGNvbG9yID0gU3BvcnQuMiwgZmlsbCA9IFNwb3J0LjIpKSArIA0KICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjUpICsgDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoJyNDRkI4N0MnLCAnIzAwMDAwMCcpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCcjQ0ZCODdDJywgJyMwMDAwMDAnKSkgKw0KICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBNZWFuIENvbnRhY3QgVGltZSBBY3Jvc3MgU3BvcnRzJywNCiAgICAgICB4ID0gJ01lYW4gQ29udGFjdCBUaW1lIChzKScsDQogICAgICAgeSA9ICdEZW5zaXR5JywNCiAgICAgICBmaWxsID0gJ1Nwb3J0IFR5cGUnLA0KICAgICAgIGNvbG9yID0gJ1Nwb3J0IFR5cGUnKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoZnJvbSA9IDAsIHRvID0gNywgYnkgPSAwLjA0KSkgKyANCiAgdGhlbWVfYncoKQ0KYGBgDQoNCmBgYHtyfQ0KI3JlYWRzIGluIHRoZSBpbWFnZSBvZiB0aGUgbm9ybWF0aXZlIGRhdGEgYW5kIG5vcm1hbGl6ZXMgdGhlIHNpemUNCmltZyA8LSBpbWFnZV9yZWFkKCJoamNvbnRhY3Rfd2x4LnBuZyIpDQppbWdfZ3JvYiA8LSByYXN0ZXJHcm9iKGltZywgaW50ZXJwb2xhdGUgPSBUUlVFKQ0KaW1nX3Bsb3QgPC0gZ2dkcmF3KCkgKyBkcmF3X2dyb2IoaW1nX2dyb2IsIHggPSAwLCB5ID0gMCwgd2lkdGggPSAxLCBoZWlnaHQgPSAxKQ0KDQojY3JlYXRlcyBhIHBsb3Qgb2YgdGhlIENVIGRhdGEgbmFtZWQgInAiDQpwIDwtIGdncGxvdChISl9MLCBhZXMoeCA9IE1lYW4uQ29udGFjdC5UaW1lLi5tcy4pKSArIA0KICBnZW9tX2RlbnNpdHkoZmlsbCA9ICcjQ0ZCODdDJykgKw0KICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBNZWFuIENvbnRhY3QgVGltZScsDQogICAgICAgeCA9ICdNZWFuIENvbnRhY3QgVGltZSAocyknLA0KICAgICAgIHkgPSAnRGVuc2l0eScsDQogICAgICAgY2FwdGlvbiA9ICdDVSBXb21lbnMgTGFjcm9zc2UnKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IG1lZGlhbihISl9MJE1lYW4uQ29udGFjdC5UaW1lLi5tcy4pLCBsaW5ldHlwZSA9ICdzb2xpZCcpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYyhxdWFudGlsZShISl9MJE1lYW4uQ29udGFjdC5UaW1lLi5tcy4sIHByb2JzID0gYygwLjAxLCAwLjI1LCAwLjc1LCAwLjk5KSkpLCBsaW5ldHlwZSA9ICdkYXNoZWQnKSArIA0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKGZyb20gPSAwLCB0byA9IDEwMCwgYnkgPSAwLjA0KSkgKyANCiAgdGhlbWVfYncoKQ0KDQojY29tYmluZXMgYm90aCB0aGUgQ1UgZGF0YSBkZW5zaXR5IHBsb3QgYW5kIHB1dHMgbm9ybWF0aXZlIGltYWdlIG9uIHRoZSByaWdodA0KY29tYmluZWQgPC0gcGxvdF9ncmlkKHAsIGltZ19wbG90LCANCiAgICAgICAgICAgICAgICAgICAgICByZWxfd2lkdGhzID0gYygxLjUsIDEpLCANCiAgICAgICAgICAgICAgICAgICAgICBucm93ID0gMSwgICAgICAgIyA8LSBob3Jpem9udGFsIGxheW91dA0KICAgICAgICAgICAgICAgICAgICAgIGFsaWduID0gImgiKSAgICAjIDwtIGFsaWduIGhvcml6b250YWxseSANCg0KI3ByaW50cyBmaW5hbCBncmFwaGljDQpjb21iaW5lZA0KYGBgDQoNCmBgYHtyfQ0KI2ZpbmRzIDI1dGgsIDUwdGgsIGFuZCA3NXRoIHBlcmNlbnRpbGVzIG9mIENVIGRhdGENCnF1YW50aWxlKEhKX0wkTWVhbi5Db250YWN0LlRpbWUuLm1zLiwgcHJvYnMgPSBjKDAuMjUsIDAuNSwgMC43NSkpDQpgYGANCg0KYGBge3J9DQojdXNlcyBhIHQtdGVzdCB0byB0ZXN0IGZvciBkaWZmZXJlbmNlcyBpbiBtZWFucyBiZXR3ZWVuIG9ubHkgdHdvIHNwb3J0czogZmlsdGVycyBmb3IgdGhlc2UgdHdvIHNwb3J0cw0KdC50ZXN0KE1lYW4uQ29udGFjdC5UaW1lLi5tcy4gfiBTcG9ydCwgZGF0YSA9IGhqICU+JSBmaWx0ZXIoU3BvcnQgJWluJSBjKCdMYWNyb3NzZScsICdWb2xsZXliYWxsJykpKQ0KYGBgDQoNCiMjIyBOb3JkaWMgRGF0YQ0KDQpgYGB7cn0NCiNjcmVhdGluZyBhIGRhdGFzZXQgY29udGFpbmluZyBwZXJmb3JtYW5jZSBkYXRhIGFjcm9zcyBhbGwgc3BvcnRzDQpwZXJmb3JtYW5jZV9hbGxfbm9yZGljIDwtIHJiaW5kKHBlcmZvcm1hbmNlX0Jfbm9yZGljLCBwZXJmb3JtYW5jZV9TX25vcmRpYywgcGVyZm9ybWFuY2VfTF9ub3JkaWMsIHBlcmZvcm1hbmNlX1Zfbm9yZGljKSAlPiUNCiAgbXV0YXRlKFRocmVzaCA9IGlmZWxzZShSZWxhdGl2ZS5NYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbiA+PSA1LCAnWWVzJywgJ05vJyksDQogICAgICAgICBTcG9ydC4yID0gaWZlbHNlKFNwb3J0ID09ICdCYXNrZXRiYWxsJyB8IFNwb3J0ID09ICdWb2xsZXliYWxsJywgJ0NvdXJ0JywgJ0ZpZWxkJykpDQoNCiNzdW1tYXJpemVzIGF2ZXJhZ2VzIGluIG1vc3QgaW1wb3J0YW50IHZhcmlhYmxlcyBieSBzcG9ydA0KcGVyZm9ybWFuY2VfYWxsX25vcmRpYyAlPiUNCiAgZ3JvdXBfYnkoU3BvcnQpICU+JQ0KICBzdW1tYXJpc2UoYEF2ZXJhZ2UgTWF4aW11bSBOb3JkaWMgQmlsYXRlcmFsIE1lYW5gID0gbWVhbihNYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbiksDQogICAgICAgICAgICBgQXZlcmFnZSBSZWxhdGl2ZSBNYXhpbXVtIE5vcmRpYyBCaWxhdGVyYWwgTWVhbmAgPSBtZWFuKFJlbGF0aXZlLk1heGltdW0uTm9yZGljLkJpbGF0ZXJhbC5NZWFuKSwNCiAgICAgICAgICAgIGBBdmVyYWdlIE1lYW4gSW1iYWxhbmNlYCA9IG1lYW4oTm9yZGljLk1FQU4uSW1iYWxhbmNlKSwNCiAgICAgICAgICAgIGBBdmVyYWdlIE1heCBJbWJhbGFuY2VgID0gbWVhbihOb3JkaWMuTUFYLkltYmFsYW5jZSkpDQoNCiNjcmVhdGVzIGEgc3Vic2V0IG9mIGp1c3QgdGhlIGNvdXJ0IHNwb3J0cw0KZmllbGRfYWxsIDwtIHBlcmZvcm1hbmNlX2FsbF9ub3JkaWMgJT4lDQogIGZpbHRlcihTcG9ydC4yID09ICdGaWVsZCcpDQoNCiNjcmVhdGVzIGEgc3Vic2V0IG9mIGp1c3QgdGhlIGNvdXJ0IHNwb3J0cw0KY291cnRfYWxsIDwtIHBlcmZvcm1hbmNlX2FsbF9ub3JkaWMgJT4lDQogIGZpbHRlcihTcG9ydC4yID09ICdDb3VydCcpDQpgYGANCg0KYGBge3J9DQojY3JlYXRlcyBhIGRlbnNpdHkgcGxvdCBmb3IgbWF4aW11bSBmb3JjZSBhY3Jvc3Mgc3BvcnRzDQpnZ3Bsb3QocGVyZm9ybWFuY2VfYWxsX25vcmRpYywgYWVzKHggPSBNYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbiwgY29sb3IgPSBTcG9ydCwgZmlsbCA9IFNwb3J0KSkgKyANCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC40KSArIA0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCcjQ0ZCODdDJywgJyM2NjY2NjYnLCAnIzAwMDAwMCcsICcjOEM3ODUzJykpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoJyNDRkI4N0MnLCAnIzY2NjY2NicsICcjMDAwMDAwJywgJyM4Qzc4NTMnKSkgKw0KICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBNYXhpbXVtIE5vcmRpYyBGb3JjZSBBY3Jvc3MgU3BvcnRzJywNCiAgICAgICB4ID0gJ01heGltdW0gQmlsYXRlcmFsIEF2ZXJhZ2UgRm9yY2UgKE4pJywNCiAgICAgICB5ID0gJ0RlbnNpdHknKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoZnJvbSA9IDAsIHRvID0gNjAwLCBieSA9IDUwKSkgKyANCiAgdGhlbWVfYncoKQ0KYGBgDQoNCmBgYHtyfQ0KI2NyZWF0ZXMgYSBkZW5zaXR5IHBsb3QgZm9yIG1heGltdW0gYmlsYXRlcmFsIGZvcmNlIGFjcm9zcyBzcG9ydCB0eXBlDQpnZ3Bsb3QocGVyZm9ybWFuY2VfYWxsX25vcmRpYywgYWVzKHggPSBNYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbiwgY29sb3IgPSBTcG9ydC4yLCBmaWxsID0gU3BvcnQuMikpICsgDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNSkgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygnI0NGQjg3QycsICcjMDAwMDAwJykpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoJyNDRkI4N0MnLCAnIzAwMDAwMCcpKSArDQogIGxhYnModGl0bGUgPSAnRGlzdHJpYnV0aW9uIG9mIE1heGltdW0gTm9yZGljIEZvcmNlIEFjcm9zcyBTcG9ydHMnLA0KICAgICAgIHggPSAnTWF4aW11bSBCaWxhdGVyYWwgQXZlcmFnZSBGb3JjZSAoTiknLA0KICAgICAgIHkgPSAnRGVuc2l0eScsDQogICAgICAgZmlsbCA9ICdTcG9ydCBUeXBlJywNCiAgICAgICBjb2xvciA9ICdTcG9ydCBUeXBlJykgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKGZyb20gPSAwLCB0byA9IDYwMCwgYnkgPSA1MCkpICsgDQogIHRoZW1lX2J3KCkNCmBgYA0KDQpgYGB7cn0NCiNyZWFkcyBpbiB0aGUgaW1hZ2Ugb2YgdGhlIG5vcm1hdGl2ZSBkYXRhIGFuZCBub3JtYWxpemVzIHRoZSBzaXplDQppbWcgPC0gaW1hZ2VfcmVhZCgibm9yZGljX3dseC5wbmciKQ0KaW1nX2dyb2IgPC0gcmFzdGVyR3JvYihpbWcsIGludGVycG9sYXRlID0gVFJVRSkNCmltZ19wbG90IDwtIGdnZHJhdygpICsgZHJhd19ncm9iKGltZ19ncm9iLCB4ID0gMCwgeSA9IDAsIHdpZHRoID0gMSwgaGVpZ2h0ID0gMSkNCg0KI2NyZWF0ZXMgYSBwbG90IG9mIHRoZSBDVSBkYXRhIG5hbWVkICJwIg0KcCA8LSBnZ3Bsb3QocGVyZm9ybWFuY2VfTF9ub3JkaWMsIGFlcyh4ID0gTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4pKSArIA0KICBnZW9tX2RlbnNpdHkoZmlsbCA9ICcjQ0ZCODdDJykgKw0KICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBNYXhpbXVtIE5vcmRpYyBGb3JjZScsDQogICAgICAgeCA9ICdNYXhpbXVtIEJpbGF0ZXJhbCBBdmVyYWdlIEZvcmNlIChOKScsDQogICAgICAgeSA9ICdEZW5zaXR5JywNCiAgICAgICBjYXB0aW9uID0gJ0NVIFdvbWVucyBMYWNyb3NzZScpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVkaWFuKHBlcmZvcm1hbmNlX0xfbm9yZGljJE1heGltdW0uTm9yZGljLkJpbGF0ZXJhbC5NZWFuKSwgbGluZXR5cGUgPSAnc29saWQnKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMocXVhbnRpbGUocGVyZm9ybWFuY2VfTF9ub3JkaWMkTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4sIHByb2JzID0gYygwLjAxLCAwLjI1LCAwLjc1LCAwLjk5KSkpLCBsaW5ldHlwZSA9ICdkYXNoZWQnKSArIA0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKGZyb20gPSAwLCB0byA9IDEwMDAsIGJ5ID0gNTApKSArIA0KICB0aGVtZV9idygpDQoNCiNjb21iaW5lcyBib3QgdGhlIENVIGRhdGEgZGVuc2l0eSBwbG90IGFuZCBwdXRzIG5vcm1hdGl2ZSBpbWFnZSBvbiB0aGUgcmlnaHQNCmNvbWJpbmVkIDwtIHBsb3RfZ3JpZChwLCBpbWdfcGxvdCwgDQogICAgICAgICAgICAgICAgICAgICAgcmVsX3dpZHRocyA9IGMoMS41LCAxKSwgDQogICAgICAgICAgICAgICAgICAgICAgbnJvdyA9IDEsICAgICAgICMgPC0gaG9yaXpvbnRhbCBsYXlvdXQNCiAgICAgICAgICAgICAgICAgICAgICBhbGlnbiA9ICJoIikgICAgIyA8LSBhbGlnbiBob3Jpem9udGFsbHkNCg0KI3ByaW50cyBmaW5hbCBncmFwaGljDQpjb21iaW5lZA0KYGBgDQoNClRoZSBsYXJnZSBvdXRsaWVycyBhcmUgSURfNjkgaW4gd29tZW5zIGxhY3Jvc3NlIGFuZCBJRF8zIGluIHdvbWVucyBzb2NjZXIuIElEXzY5IGRpZCBub3QgYXBwZWFyIGluIHRoZSBpbmNpZGVudCByZXBvcnQgYXQgYWxsLiBJRF8zIGFwcGVhcmVkIDMgdGltZXMgaW4gdGhlIGluY2lkZW50IHJlcG9ydCB3aXRoIFJpZ2h0IEtuZWUgUGFpbi9Jbmp1cnkgTm90IG90aGVyd2lzZSBzcGVjaWZpZWQgLSAwNS8wOC8yMDI0LCBMZWZ0IFF1YWRyaWNlcHMgc3RyYWluL3RlYXIgLSAwMy8wNi8yMDI0LCBSaWdodCBHbHV0ZXVzIG1lZGl1cy9taW5pbXVzIHN0cmFpbiAtIDEwLzAyLzIwMjQuIFRoZSBvYnNlcnZhdGlvbiBmb3IgcGVyZm9ybWFuY2Ugc3RyZW5ndGggd2FzIDAyLzAzLzIwMjUgd2hpY2ggaW5kaWNhdGVzIGl0IG9jY3VyZWQgYWZ0ZXIgYWxsIG9mIGhlciBpbmp1cmllcy4gQm90aCBhdGhsZXRlcyBhbHNvIGhhdmUgYSBoYW5kZnVsIG9mIG90aGVyIG9ic2VydmF0aW9ucyB0aGF0IGZpdCBpbnRvIHRoZSBjZW50ZXIgb2YgdGhlIGRpc3RyaWJ1dGlvbi4NCg0KYGBge3J9DQojZmluZHMgMjV0aCwgNTB0aCwgYW5kIDc1dGggcGVyY2VudGlsZXMgb2YgQ1UgZGF0YQ0KcXVhbnRpbGUocGVyZm9ybWFuY2VfTF9ub3JkaWMkTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4sIHByb2JzID0gYygwLjI1LCAwLjUsIDAuNzUpKQ0KYGBgDQoNCmBgYHtyfQ0KI3BlcmZvcm1zIGEgV2VsY2gncyBULXRlc3QgZm9yIGRpZmZlcmVuY2Ugb2YgbWVhbnMgYmV0d2VlbiB2YXJpYWJsZXMgb2YgaW50ZXJlc3QgYW5kIHNwb3J0IHR5cGUNCnQudGVzdChNYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbiB+IFNwb3J0LjIsIGRhdGEgPSBwZXJmb3JtYW5jZV9hbGxfbm9yZGljLCBhbHRlcm5hdGl2ZSA9ICdncmVhdGVyJykNCnQudGVzdChSZWxhdGl2ZS5NYXhpbXVtLk5vcmRpYy5CaWxhdGVyYWwuTWVhbiB+IFNwb3J0LjIsIGRhdGEgPSBwZXJmb3JtYW5jZV9hbGxfbm9yZGljLCBhbHRlcm5hdGl2ZSA9ICdsZXNzJykNCnQudGVzdChOb3JkaWMuTUVBTi5JbWJhbGFuY2UgfiBTcG9ydC4yLCBkYXRhID0gcGVyZm9ybWFuY2VfYWxsX25vcmRpYykNCnQudGVzdChJbXB1bHNlIH4gU3BvcnQuMiwgZGF0YSA9IHBlcmZvcm1hbmNlX2FsbF9ub3JkaWMsIGFsdGVybmF0aXZlID0gJ2dyZWF0ZXInKQ0KdC50ZXN0KEZvcmNlLkRpZmYuTm9ybSB+IFNwb3J0LjIsIGRhdGEgPSBwZXJmb3JtYW5jZV9hbGxfbm9yZGljLCBhbHRlcm5hdGl2ZSA9ICdncmVhdGVyJykNCmBgYA0KDQpUaGVyZSBpcyBhIGxvdCBvZiBzdGF0aXN0aWNhbCBldmlkZW5jZSBmb3IgYSBkaWZmZXJlbmNlIGluIHRoZSBtZWFucyBvZiBjb3VydCBzcG9ydHMgdnMgZmllbGQgc3BvcnRzIGluIG1heGltdW0gbm9yZGljIGJpbGF0ZXJhbCBtZWFuIGZvcmNlLiBUaGVyZSBpcyBsZXNzIGJ1dCBzdGlsbCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGV2aWRlbmNlIGZvciBhIGRpZmZlcmVuY2UgaW4gdGhlIGF2ZXJhZ2UgaW1iYWxhbmNlIGFuZCBtYXggaW1iYWxhbmNlIGJldHdlZW4gc3BvcnQgdHlwZXMgd2l0aCBmaWVsZCBzcG9ydHMgdHlwaWNhbGx5IGhhdmluZyBtb3JlIGltYmFsYW5jZS4gDQoNCmBgYHtyfQ0KI3BlcmZvcm1zIGEgV2VsY2gncyBULXRlc3QgZm9yIGRpZmZlcmVuY2Ugb2YgbWVhbnMgd2l0aGluIGNvdXJ0IHNwb3J0cw0KdC50ZXN0KE1heGltdW0uTm9yZGljLkJpbGF0ZXJhbC5NZWFuIH4gU3BvcnQsIGRhdGEgPSBjb3VydF9hbGwpDQp0LnRlc3QoUmVsYXRpdmUuTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4gfiBTcG9ydCwgZGF0YSA9IGNvdXJ0X2FsbCkNCnQudGVzdChOb3JkaWMuTUVBTi5JbWJhbGFuY2UgfiBTcG9ydCwgZGF0YSA9IGNvdXJ0X2FsbCkNCnQudGVzdChJbXB1bHNlIH4gU3BvcnQsIGRhdGEgPSBjb3VydF9hbGwpDQp0LnRlc3QoRm9yY2UuRGlmZi5Ob3JtIH4gU3BvcnQsIGRhdGEgPSBjb3VydF9hbGwpDQpgYGANCg0KVGhlcmUgaXMgYSB2ZXJ5IHNtYWxsIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGVzZSB0d28gc3BvcnRzLCB3aXRoIGJhc2tldGJhbGwgYmVpbmcgc2xpZ2h0bHkgc3Ryb25nZXIsIGJ1dCB0aGUgcC12YWx1ZSBpcyBhbG1vc3Qgc2lnbmlmaWNhbnQgYXQgdGhlIDAuMDUgbGV2ZWwuIE5vIHN0YXRpc3RpY2FsIHNpZ25maWNhbmNlIGluIHRlcm1zIG9mIGltYmFsYW5jZS4gDQoNCmBgYHtyfQ0KI3BlcmZvcm1zIGEgV2VsY2gncyBULXRlc3QgZm9yIGRpZmZlcmVuY2Ugb2YgbWVhbnMgd2l0aGluIGNvdXJ0IHNwb3J0cw0KdC50ZXN0KE1heGltdW0uTm9yZGljLkJpbGF0ZXJhbC5NZWFuIH4gU3BvcnQsIGRhdGEgPSBmaWVsZF9hbGwpDQp0LnRlc3QoUmVsYXRpdmUuTWF4aW11bS5Ob3JkaWMuQmlsYXRlcmFsLk1lYW4gfiBTcG9ydCwgZGF0YSA9IGZpZWxkX2FsbCkNCnQudGVzdChOb3JkaWMuTUVBTi5JbWJhbGFuY2UgfiBTcG9ydCwgZGF0YSA9IGZpZWxkX2FsbCkNCnQudGVzdChJbXB1bHNlIH4gU3BvcnQsIGRhdGEgPSBmaWVsZF9hbGwpDQp0LnRlc3QoRm9yY2UuRGlmZi5Ob3JtIH4gU3BvcnQsIGRhdGEgPSBmaWVsZF9hbGwpDQpgYGANCg0KVGhlcmUgaXMgYSBsb3Qgb2Ygc3RhdGlzdGljYWwgZXZpZGVuY2UgdGhhdCB0aGVyZSBpcyBhIGRpZmZlcmVuY2UgaW4gdGhlIG1lYW5zIG9mIG1heGltdW0gbm9yZGljIGJpbGF0ZXJhbCBtZWFuIGZvcmNlIGJldHdlZW4gdGhlIGZpZWxkIHNwb3J0cyB3aXRoIHNvY2NlciBoYXZpbmcgYSBzaWduaWZpY2FudGx5IGhpZ2hlciBtZWFuIHRoYW4gbGFjcm9zc2UuIFRoZXJlIGlzIHN0YXRpc3RpY2FsIGV2aWRlbmNlIG9mIGEgZGlmZmVyZW5jZSBpbiBpbWJhbGFuY2Ugd2l0aCBsYWNyb3NzZSBoYXZpbmcgc2lnbmlmaWNhbnRseSBtb3JlIG1lYW4gYW5kIG1heCBpbWJhbGFuY2UgY29tcGFyZWQgdG8gc29jY2VyIGJ1dCBtb3N0IGxpa2VseSBhbHNvIGJhc2tldGJhbGwgYW5kIHZvbGxleWJhbGwuIA0KDQpgYGB7cn0NCiN1c2VzIHQtdGVzdCBmb3IganVzdCB0d28gc3BvcnRzIHdpdGhpbiB0aGUgbGFyZ2VyIGRhdGFzZXQNCnQudGVzdChOb3JkaWMuTUVBTi5JbWJhbGFuY2UgfiBTcG9ydCwgZGF0YSA9IHBlcmZvcm1hbmNlX2FsbF9ub3JkaWMgJT4lIGZpbHRlcihTcG9ydCAlaW4lIGMoJ1ZvbGxleWJhbGwnLCAnQmFza2V0YmFsbCcpKSkNCmBgYA0KDQpgYGB7cn0NCiNhbm92YSB0ZXN0IGZvciBkaWZmZXJlbmNlcw0KYW5vdmFfcmVzdWx0IDwtIGFvdihOb3JkaWMuTUFYLkltYmFsYW5jZSB+IFNwb3J0LCBkYXRhID0gcGVyZm9ybWFuY2VfYWxsX25vcmRpYykNCnN1bW1hcnkoYW5vdmFfcmVzdWx0KQ0KYGBgDQoNClVzaW5nIHRoZSBhbm92YSB0ZXN0IHRoZXJlIGlzIHNsaWdodCBzdGF0aXN0aWNhbCBldmlkZW5jZSBvZiBhIGRpZmZlcmVuY2UgaW4gbWVhbiBpbWJhbGFuY2UgYmV0d2VlbiBzcG9ydHMgYW5kIG1vcmUgZm9yIG1heCBpbWJhbGFuY2UgYmV0d2VlbiBzcG9ydHMuIA0KDQojIyMgSGlwIERhdGENCg0KYGBge3J9DQojY3JlYXRpbmcgYSBkYXRhc2V0IGNvbnRhaW5pbmcgcGVyZm9ybWFuY2UgaGlwIGRhdGEgYWNyb3NzIGFsbCBzcG9ydHMNCnBlcmZvcm1hbmNlX2FsbF9oaXAgPC0gcmJpbmQocGVyZm9ybWFuY2VfQl9oaXAsIHBlcmZvcm1hbmNlX1NfaGlwLCBwZXJmb3JtYW5jZV9MX2hpcCwgcGVyZm9ybWFuY2VfVl9oaXApICU+JQ0KICBtdXRhdGUoQXZnLkFiZC5NZWFuID0gKEhpcC5BYmQuTGVmdC5NRUFOICsgSGlwLkFiZC5SaWdodC5NRUFOKSAvIDIsDQogICAgICAgICBBdmcuQWRkLk1lYW4gPSAoSGlwLkFkZC5MZWZ0Lk1FQU4gKyBIaXAuQWRkLlJpZ2h0Lk1FQU4pIC8gMiwNCiAgICAgICAgIEF2Zy5BYmQuTWF4ID0gKEhpcC5BYmQuTGVmdC5NQVggKyBIaXAuQWJkLlJpZ2h0Lk1BWCkgLyAyLA0KICAgICAgICAgQXZnLkFkZC5NYXggPSAoSGlwLkFkZC5MZWZ0Lk1BWCArIEhpcC5BZGQuUmlnaHQuTUFYKSAvIDIsDQogICAgICAgICBSZWxhdGl2ZS5BYmQuTWVhbiA9IEF2Zy5BYmQuTWVhbiAvIEF0aGxldGUuQm9keXdlaWdodC4ua2cuLA0KICAgICAgICAgUmVsYXRpdmUuQWRkLk1lYW4gPSBBdmcuQWRkLk1lYW4gLyBBdGhsZXRlLkJvZHl3ZWlnaHQuLmtnLiwNCiAgICAgICAgIFJlbGF0aXZlLkFiZC5NYXggPSBBdmcuQWJkLk1heCAvIEF0aGxldGUuQm9keXdlaWdodC4ua2cuLA0KICAgICAgICAgUmVsYXRpdmUuQWRkLk1heCA9IEF2Zy5BZGQuTWF4IC8gQXRobGV0ZS5Cb2R5d2VpZ2h0Li5rZy4sDQogICAgICAgICBTcG9ydC4yID0gaWZlbHNlKFNwb3J0ID09ICdCYXNrZXRiYWxsJyB8IFNwb3J0ID09ICdWb2xsZXliYWxsJywgJ0NvdXJ0JywgJ0ZpZWxkJykpDQoNCiNzdW1tYXJpemVzIGF2ZXJhZ2VzIGZvciB2YXJpYWJsZXMgb2YgaW50ZXJlc3Qgd2l0aGluIGVhY2ggc3BvcnQgDQpwZXJmb3JtYW5jZV9hbGxfaGlwICU+JQ0KICBncm91cF9ieShTcG9ydCkgJT4lDQogIHN1bW1hcmlzZShgQXZlcmFnZSBBYmQuIE1lYW5gID0gbWVhbihBdmcuQWJkLk1lYW4pLA0KICAgICAgICAgICAgYEF2ZXJhZ2UgQWRkLiBNZWFuYCA9IG1lYW4oQXZnLkFkZC5NZWFuKSwNCiAgICAgICAgICAgIGBBdmVyYWdlIEFiZC4gTWF4YCA9IG1lYW4oQXZnLkFiZC5NYXgpLA0KICAgICAgICAgICAgYEF2ZXJhZ2UgQWRkLiBNYXhgID0gbWVhbihBdmcuQWRkLk1heCksDQogICAgICAgICAgICBgQXZlcmFnZSBSZWwuIEFiZC4gTWVhbmAgPSBtZWFuKFJlbGF0aXZlLkFiZC5NZWFuKSwNCiAgICAgICAgICAgIGBBdmVyYWdlIFJlbC4gQWRkLiBNZWFuYCA9IG1lYW4oUmVsYXRpdmUuQWRkLk1lYW4pLA0KICAgICAgICAgICAgYEF2ZXJhZ2UgUmVsLiBBYmQuIE1heGAgPSBtZWFuKFJlbGF0aXZlLkFiZC5NYXgpLA0KICAgICAgICAgICAgYEF2ZXJhZ2UgUmVsLiBBZGQuIE1heGAgPSBtZWFuKFJlbGF0aXZlLkFkZC5NYXgpKQ0KDQojY3JlYXRlcyBhIHN1YnNldCBvZiBqdXN0IHRoZSBmaWVsZCBzcG9ydHMNCmZpZWxkX2FsbF9oaXAgPC0gcGVyZm9ybWFuY2VfYWxsX2hpcCAlPiUNCiAgZmlsdGVyKFNwb3J0LjIgPT0gJ0ZpZWxkJykNCg0KI2NyZWF0ZXMgYSBzdWJzZXQgb2YganVzdCB0aGUgY291cnQgc3BvcnRzDQpjb3VydF9hbGxfaGlwIDwtIHBlcmZvcm1hbmNlX2FsbF9oaXAgJT4lDQogIGZpbHRlcihTcG9ydC4yID09ICdDb3VydCcpDQpgYGANCg0KYGBge3J9DQojY3JlYXRlcyBhIGRlbnNpdHkgcGxvdCBvZiBoaXAgYWJkdWN0aW9uL2FkZHVjdGlvbiBpbXB1bHNlIGFjcm9zcyB0aGUgNCBzcG9ydHMNCmdncGxvdChwZXJmb3JtYW5jZV9hbGxfaGlwLCBhZXMoeCA9IEltcHVsc2UsIGZpbGwgPSBTcG9ydCwgY29sb3IgPSBTcG9ydCkpICsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC40KSArIA0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCcjQ0ZCODdDJywgJyM2NjY2NjYnLCAnIzAwMDAwMCcsICcjOEM3ODUzJykpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoJyNDRkI4N0MnLCAnIzY2NjY2NicsICcjMDAwMDAwJywgJyM4Qzc4NTMnKSkgKw0KICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBBYmQvQWRkIEltcHVsc2UgQWNyb3NzIFNwb3J0cycsDQogICAgICAgeCA9ICdJbXB1bHNlJywNCiAgICAgICB5ID0gJ0RlbnNpdHknKSArDQogIHRoZW1lX2J3KCkNCmBgYA0KDQpgYGB7cn0NCiNjcmVhdGVzIGEgZGVuc2l0eSBwbG90IGZvciBoaXAgYWJkdWN0aW9uL2FkZHVjdGlvbiBpbXB1bHNlIGFjcm9zcyBzcG9ydCB0eXBlDQpnZ3Bsb3QocGVyZm9ybWFuY2VfYWxsX2hpcCwgYWVzKHggPSBJbXB1bHNlLCBjb2xvciA9IFNwb3J0LjIsIGZpbGwgPSBTcG9ydC4yKSkgKyANCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC41KSArIA0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCcjQ0ZCODdDJywgJyMwMDAwMDAnKSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygnI0NGQjg3QycsICcjMDAwMDAwJykpICsNCiAgbGFicyh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgQWJkL0FkZCBJbXB1bHNlIEFjcm9zcyBTcG9ydHMnLA0KICAgICAgIHggPSAnSW1wdWxzZScsDQogICAgICAgeSA9ICdEZW5zaXR5JywNCiAgICAgICBmaWxsID0gJ1Nwb3J0IFR5cGUnLA0KICAgICAgIGNvbG9yID0gJ1Nwb3J0IFR5cGUnKSArDQogIHRoZW1lX2J3KCkNCmBgYA0KDQpgYGB7cn0NCiNyZWFkcyBpbiB0aGUgaW1hZ2Ugb2YgdGhlIG5vcm1hdGl2ZSBkYXRhIGFuZCBub3JtYWxpemVzIHRoZSBzaXplDQppbWcgPC0gaW1hZ2VfcmVhZCgiYWRkX3diYi5wbmciKQ0KaW1nX2dyb2IgPC0gcmFzdGVyR3JvYihpbWcsIGludGVycG9sYXRlID0gVFJVRSkNCmltZ19wbG90IDwtIGdnZHJhdygpICsgZHJhd19ncm9iKGltZ19ncm9iLCB4ID0gMCwgeSA9IDAsIHdpZHRoID0gMSwgaGVpZ2h0ID0gMSkNCg0KI2NyZWF0ZXMgYSBwbG90IG9mIHRoZSBDVSBkYXRhIG5hbWVkICJwIg0KcCA8LSBnZ3Bsb3QocGVyZm9ybWFuY2VfQl9oaXAsIGFlcyh4ID0gQXZnLkFkZC5NYXgpKSArIA0KICBnZW9tX2RlbnNpdHkoZmlsbCA9ICcjQ0ZCODdDJykgKw0KICBsYWJzKHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBNYXhpbXVtIEFkZHVjdGlvbiBGb3JjZScsDQogICAgICAgeCA9ICdNYXhpbXVtIEFkZHVjdGlvbiBGb3JjZSAoTiknLA0KICAgICAgIHkgPSAnRGVuc2l0eScsDQogICAgICAgY2FwdGlvbiA9ICdDVSBXb21lbnMgQmFza2V0YmFsbCcpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVkaWFuKHBlcmZvcm1hbmNlX0JfaGlwJEF2Zy5BZGQuTWF4KSwgbGluZXR5cGUgPSAnc29saWQnKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMocXVhbnRpbGUocGVyZm9ybWFuY2VfQl9oaXAkQXZnLkFkZC5NYXgsIHByb2JzID0gYygwLjAxLCAwLjI1LCAwLjc1LCAwLjk5KSkpLCBsaW5ldHlwZSA9ICdkYXNoZWQnKSArIA0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKGZyb20gPSAwLCB0byA9IDEwMDAsIGJ5ID0gNTApKSArIA0KICB0aGVtZV9idygpDQoNCiNjb21iaW5lcyBib3RoIHRoZSBDVSBkYXRhIGRlbnNpdHkgcGxvdCBhbmQgcHV0cyBub3JtYXRpdmUgaW1hZ2Ugb24gdGhlIHJpZ2h0DQpjb21iaW5lZCA8LSBwbG90X2dyaWQocCwgaW1nX3Bsb3QsIA0KICAgICAgICAgICAgICAgICAgICAgIHJlbF93aWR0aHMgPSBjKDEuNSwgMSksIA0KICAgICAgICAgICAgICAgICAgICAgIG5yb3cgPSAxLCAgICAgICAjIDwtIGhvcml6b250YWwgbGF5b3V0DQogICAgICAgICAgICAgICAgICAgICAgYWxpZ24gPSAiaCIpICAgICMgPC0gYWxpZ24gaG9yaXpvbnRhbGx5IA0KDQojcHJpbnRzIGZpbmFsIGdyYXBoaWMNCmNvbWJpbmVkDQpgYGANCg0KYGBge3J9DQojcGVyZm9ybXMgYSBXZWxjaCdzIFQtdGVzdCBmb3IgZGlmZmVyZW5jZSBvZiBtZWFucyBiZXR3ZWVuIHZhcmlhYmxlcyBvZiBpbnRlcmVzdCBieSBzcG9ydCB0eXBlDQp0LnRlc3QoQXZnLkFiZC5NYXggfiBTcG9ydC4yLCBkYXRhID0gcGVyZm9ybWFuY2VfYWxsX2hpcCwgYWx0ZXJuYXRpdmUgPSAnZ3JlYXRlcicpDQp0LnRlc3QoQXZnLkFkZC5NYXggfiBTcG9ydC4yLCBkYXRhID0gcGVyZm9ybWFuY2VfYWxsX2hpcCwgYWx0ZXJuYXRpdmUgPSAnZ3JlYXRlcicpDQp0LnRlc3QoUmVsYXRpdmUuQWJkLk1heCB+IFNwb3J0LjIsIGRhdGEgPSBwZXJmb3JtYW5jZV9hbGxfaGlwLCBhbHRlcm5hdGl2ZSA9ICdncmVhdGVyJykNCnQudGVzdChSZWxhdGl2ZS5BZGQuTWF4IH4gU3BvcnQuMiwgZGF0YSA9IHBlcmZvcm1hbmNlX2FsbF9oaXAsIGFsdGVybmF0aXZlID0gJ2dyZWF0ZXInKQ0KYGBgDQoNClRoZXJlIGlzIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIHRoZSBtZWFucyB2YWx1ZXMgb2YgYXZlcmFnZSBhZGR1Y3Rpb24gYW5kIGFiZHVjdGlvbiBtYXggYmV0d2VlbiB0aGUgY291cnQgYW5kIGZpZWxkIHNwb3J0cy4gVGhpcyBpcyBhbHNvIHRydWUgZm9yIHRoZSByZWxhdGl2ZSBhZGR1Y3Rpb24gYW5kIGFiZHVjdGlvbiBtYXgsIGFsdGhvdWdoIHNsaWdodGx5IGxlc3Mgc2lnbmlmaWNhbnQuIFRoZSBzYW1lIGFwcGxpZXMgZm9yIHRoZSBtZWFuIGFiZHVjdGlvbi9hZGR1Y3Rpb24gc3RhdHMgYXMgd2VsbC4gDQoNCmBgYHtyfQ0KI3BlcmZvcm1zIGEgV2VsY2gncyBULXRlc3QgZm9yIGRpZmZlcmVuY2Ugb2YgbWVhbnMgd2l0aGluIGNvdXJ0IHNwb3J0cw0KdC50ZXN0KEF2Zy5BYmQuTWF4IH4gU3BvcnQsIGRhdGEgPSBjb3VydF9hbGxfaGlwKQ0KdC50ZXN0KEF2Zy5BZGQuTWF4IH4gU3BvcnQsIGRhdGEgPSBjb3VydF9hbGxfaGlwKQ0KdC50ZXN0KFJlbGF0aXZlLkFiZC5NYXggfiBTcG9ydCwgZGF0YSA9IGNvdXJ0X2FsbF9oaXApDQp0LnRlc3QoUmVsYXRpdmUuQWRkLk1heCB+IFNwb3J0LCBkYXRhID0gY291cnRfYWxsX2hpcCkNCmBgYA0KDQpUaGVyZSBpcyBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiB0aGUgbWVhbnMgb2YgYXZlcmFnZSBhYmR1Y3Rpb24gbWF4IHdpdGggYmFza2V0YmFsbCBiZWluZyBoaWdoZXIgYW5kIHJlbGF0aXZlIGFkZHVjdGlvbiBtYXggd2l0aCB2b2xsZXliYWxsIGJlaW5nIGhpZ2hlci4gQWxzbyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IGF2ZXJhZ2UgYWRkdWN0aW9uIG1heHMgYXJlIGFsbW9zdCBpZGVudGljYWwgYmV0d2VlbiB0aGUgc3BvcnRzIGFuZCBoYXZlIGEgcC12YWx1ZSBvZiAwLjk2NzEuIFZvbGxleWJhbGwgaXMgZ3JlYXRlciBpbiB0ZXJtcyBvZiByZWxhdGl2ZSBmb3JjZSBpbiBib3RoLiANCg0KYGBge3J9DQojcGVyZm9ybXMgYSBXZWxjaCdzIFQtdGVzdCBmb3IgZGlmZmVyZW5jZSBvZiBtZWFucyB3aXRoaW4gZmllbGQgc3BvcnRzDQp0LnRlc3QoQXZnLkFiZC5NYXggfiBTcG9ydCwgZGF0YSA9IGZpZWxkX2FsbF9oaXApDQp0LnRlc3QoQXZnLkFkZC5NYXggfiBTcG9ydCwgZGF0YSA9IGZpZWxkX2FsbF9oaXApDQp0LnRlc3QoUmVsYXRpdmUuQWJkLk1heCB+IFNwb3J0LCBkYXRhID0gZmllbGRfYWxsX2hpcCkNCnQudGVzdChSZWxhdGl2ZS5BZGQuTWF4IH4gU3BvcnQsIGRhdGEgPSBmaWVsZF9hbGxfaGlwKQ0KYGBgDQoNCk1vc3QgYXJlIGFsbW9zdCBzaWduaWZpY2FudCB3aXRoIHRoZSBkaWZmZXJlbmNlIGluIGF2ZXJhZ2UgYWRkdWN0aW9uIG1heCBiZWluZyB2ZXJ5IHNpZ25pZmljYW50LiBTb2NjZXIgaXMgZ3JlYXRlciBpbiBib3RoIHN0cmVuZ3RoIGZvcmNlcyBvbiBhdmVyYWdlIGFuZCB0aGUgcmVsYXRpdmUgYWRkdWN0aW9uIGJ1dCBsYWNyb3NzIGlzIHN0cm9uZ2VyIG9uIGF2ZXJhZ2UgaW4gdGhlIHJlbGF0aXZlIGFiZHVjdGlvbi4gDQoNCmBgYHtyfQ0KI2Fub3ZhIHRlc3QgZm9yIGRpZmZlcmVuY2VzDQphbm92YV9yZXN1bHQgPC0gYW92KEJpbGF0ZXJhbC5IaXAuQWJkdWN0aW9uLkFkZHVjdGlvbi5SYXRpbyB+IFNwb3J0LCBkYXRhID0gcGVyZm9ybWFuY2VfYWxsX2hpcCkNCnN1bW1hcnkoYW5vdmFfcmVzdWx0KQ0KYGBgDQoNClVzaW5nIGFub3ZhIHRlc3QgdGhlcmUgaXMgbm8gc3RhdGlzdGljYWwgZXZpZGVuY2Ugb2YgYSBkaWZmZXJlbmNlIGluIG1lYW5zIGJldHdlZW4gc3BvcnRzIGZvciBhdmVyYWdlL21heCBoaXAgYWRkdWN0aW9uIGltYmFsYW5jZSBvciBiaWxhdGVyYWwgaGlwIGFiZHVjdGlvbiBhZGR1Y3Rpb24gcmF0aW8uIFRoZXJlIGlzIGhvd2V2ZXIgdmVyeSBzbGlnaHQgc3RhdGlzdGljYWwgZXZpZGVuY2Ugb2YgYSBkaWZmZXJlbmNlIGluIG1lYW5zIGJldHdlZW4gdGhlIHNwb3J0cyBmb3IgYXZlcmFnZS9tYXggaGlwIGFiZHVjdGlvbiBpbWJhbGFuY2UuIA0KDQpgYGB7cn0NCiN1c2VzIHdlbGNoIHR3byBzYW1wbGUgdC10ZXN0IGZvciBkaWZmZXJlbmNlIG9mIG1lYW5zIGJldHdlZW4gdHdvIHNwb3J0cyBmaWx0ZXJlZCBmb3INCnQudGVzdChJbXB1bHNlIH4gU3BvcnQsIGRhdGEgPSBwZXJmb3JtYW5jZV9hbGxfaGlwICU+JSBmaWx0ZXIoU3BvcnQgJWluJSBjKCdTb2NjZXInLCAnQmFza2V0YmFsbCcpKSkNCmBgYA0KDQoNCg==